Introducing pre-compiled JS assets for self-hosters

:mega: Discourse now publishes pre-built JavaScript assets, which will significantly speed up installation and updates, especially for servers with limited resources.


Compiling and optimizing JavaScript assets has always been one of the most resource-intensive parts of running Discourse. As our codebase and the JavaScript ecosystem have evolved, this process has become even more demanding.

In our tests, these changes reduce the asset-build time on a 1GB RAM Digital Ocean droplet from 45 minutes to just 3 minutes.

How does it work?

On every commit merged to main, a GitHub Actions workflow builds and bundles the assets into .tar.gz files (one for production, one for development). These bundles are published via GitHub releases in a dedicated repository. We ensure assets are published before any commit moves to tests-passed.

When building your own site, Discourse now checks for a matching pre-built bundle and downloads it. Plugins are then built on top. If no bundle is found or there’s an error, Discourse falls back to building from source.

Does this impact end-users?

No. Assets are still served to end-users from your own server / CDN.

Can I opt out?

Yes! If you prefer to build your own assets and have a sufficiently powerful server, set DISCOURSE_DOWNLOAD_PRE_BUILT_ASSETS: 0 in your app.yml file.

What if I’m running a forked or patched version of Discourse?

Asset bundles are named by commit hash. If you’re running a fork, no bundle will be found and assets will build from source. If your Discourse copy is patched (i.e., the git working tree isn’t clean), Discourse will not attempt to download a bundle.

What about other asset-related build steps?

Currently, this optimization applies only to core JS assets. In the future, we may expand it to some plugins and other steps like gz/brotli compression.

What about the stable branch?

Pre-built assets for the stable branch will be published starting with the next major version bump, planned for August 2025.

48 Likes

Just did a rebuild of https://discourse-on-a-pi5.falco.dev/ and it took just 3 minutes and 35s, this is very impressive!

23 Likes

Two container setup and without database ~8 minutes.

5 Likes

Whoa :scream: :person_bowing:

I don’t have this option in my config, do I need to add it with a value of 1 so I can opt in? Or will all this just magically happen when I next update?

FYI this is what happens when your installation doesn’t meet the criteria:

I, [2025-08-01T06:43:09.560655 #1]  INFO -- : > cd /var/www/discourse && su discourse -c 'bundle exec rake assets:precompile:build'
[assemble_ember_build] Node.js heap_size_limit is less than 2048MB. Setting --max-old-space-size=2048 and CHEAP_SOURCE_MAPS=1
[assemble_ember_build] No existing build info file found.
[assemble_ember_build] Git working directory is not clean. Cannot download prebuilt assets.
[assemble_ember_build] Running full core build...

I’m doing some tweaks to config/initializers/100-sidekiq.rb in app.yml to add support for a retry count on all sidekiq jobs (which I presume is the only way to achieve this and not within a plugin? But could revisit) so I believe this is enough not to meet the criteria …

2 Likes

It’s enabled by default. You only need to specify the config if you want to opt-out.

Yeah exactly. Any kind of diff in the git repo will cause it to bail out.

Re. the sidekiq thing, if you open a topic about it, I’m sure we can work out a way to do it either from a plugin, or maybe we could introduce a new GlobalSetting for it.

4 Likes

btw, a very simple way to time your builds without having to remain present at your console is the following:

time ./launcher rebuild app

(or whatever flavour of container if you aren’t using just one container)

which will report the elapsed time at the conclusion of the build :stopwatch:

11 Likes

Nice change. I get a

real 2m41.898s
user 0m0.372s
sys 0m0.583s

Thank you for your work

4 Likes

Wow Impressive has been date defined? my version is a81eaacb1c53581912519ae6574fa3523ef215dd I should wait to rebuild?

Oh nice :star_struck:

Thanks for that @merefield - can’t believe I’m only finding this out now after 7 years and several hundred cmd line rebuilds :grin:

5 Likes

If you are following our standard release channel you can rebuild now and reap the benefits.

4 Likes

The Only Ones! thank you.

1 Like

4 minutos to rebuild I did this a couple times today fully migrated! Impressive Discourse! next rebuild I’ll remind to use that beautiful command thanks all.

1 Like

Maybe it’s an idea to limit this to app/assets, config/locales for core and plugins? Right now this will also cause a complete rebuild when Ruby-only (security) patches have been applied.

Yeah it’s possible we can restrict this further. Although for the case of security patches, it’s quite common for them to affect the JS app as well… so a full rebuild will still be necessary.

2 Likes

Just tried it, it’s fantastic, ~3min! What a smart and amazing feature. :star_struck:
It makes me want to install every existing plugin one by one now. :rofl:

3 Likes