# Introducing a new build system for plugins

**URL:** https://meta.discourse.org/t/introducing-a-new-build-system-for-plugins/398713
**Category:** Development
**Tags:** dev-news
**Created:** [March 18, 2026, 12:14pm UTC](https://meta.discourse.org/t/introducing-a-new-build-system-for-plugins/398713 "2026-03-18T12:14:37Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [March 18, 2026, 12:14pm UTC](https://meta.discourse.org/t/introducing-a-new-build-system-for-plugins/398713/1 "2026-03-18T12:14:37Z")

</div>

Over the last few months, we’ve been working on a new build system for plugin JavaScript code. This will bring plugins up-to-date with the changes we made to the theme build system back in July 2025, which lean on more modern browser technologies and JS build tooling.

**This change is largely backwards-compatible. Most plugin authors won’t need to do anything.** 🎉

### Benefits

As well as the behind-the-scenes modernization, this change will bring a number of functional benefits to Discourse developers & hosters:

1. Plugin assets are heavily cached, and are keyed on a per-plugin basis. This means that restarting your server in development will not have to rebuild all plugins from scratch.

2. We can start to include precompiled code for popular plugins in [our existing asset bundles](https://meta.discourse.org/t/introducing-pre-compiled-js-assets-for-self-hosters/376700). During a rebuild, only changed/new plugins will need to be built. This should be especially useful for resource-constrained machines

3. Plugin code will be transpiled to a native ES module. This brings much simpler syntax, faster execution in the browser, and unlocks future use of things like `import()` for bundle-splitting in future.

### Testing / Timeline

We have been testing this system internally for some time, and have verified it’s functionality on hundreds of official plugins. Meta has been running with the new system for weeks.

If you’d like to try it out yourself, you can set the `ROLLUP_PLUGIN_COMPILER=1` environment variable.

We plan to change the default very soon. There will be a brief period where the new system can be disabled using `ROLLUP_PLUGIN_COMPILER=0`, in case of any surprises, but we intend to keep the transition period to a minimum.

### Possible issues with complex plugins

For more complex plugins, there are a few things which the new system is more strict about:

1. **Importing admin modules** from non-admin code will now raise an exception. This has always been recommended against, and would cause surprising errors. Now it is detected & blocked more deliberately.

2. **Cross-plugin imports** are still supported. However, similar to the admin modules, importing modules from a plugin which is not installed/enabled will now raise a much more obvious error. If the cross-plugin dependency is intended to be optional, then you should use core’s `optionalRequire` helper

3. **Subtle timing changes** can cause issues in rare cases. Now that plugin code is being compiled to native ES modules, anything in the module scope is being run eagerly. If you had any unusual logic in module scope, it may need to be moved into the runtime code (e.g. inside a class constructor, or similar)

If you run into any of these issues, and need a hand resolving them, don’t hesitate to post below.

### CORS / Access-Control-Allow-Origin Errors

If you experience CORS errors after the update, and you use a CDN, then you should run a full CLI rebuild (`./launcher rebuild app`) to pull in [this change](https://github.com/discourse/discourse/commit/2790b1731888c8f2396ee00b5ac3fde1ff8518ea) to the NGINX configuration.

If you use S3 (or S3 compatible) storage for assets, then you need to configure your CDN to add the `Access-Control-Allow-Origin: *` response header to all assets.

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [March 19, 2026, 6:55pm UTC](https://meta.discourse.org/t/introducing-a-new-build-system-for-plugins/398713/2 "2026-03-19T18:55:55Z")

</div>

The new compiler is now enabled by default in the `latest` version of Discourse

---

<div class="post-metadata">

### Author: ![LeoDavidson](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/leodavidson/32/119574_2.png) [@LeoDavidson](https://meta.discourse.org/u/LeoDavidson)
#### Post date: [March 20, 2026, 3:19pm UTC](https://meta.discourse.org/t/introducing-a-new-build-system-for-plugins/398713/3 "2026-03-20T15:19:17Z")

</div>

I think I have an issue with my plugin and this change:

> [@Plugin "Duplicate export" error after Discourse update](https://meta.discourse.org/t/plugin-duplicate-export-error-after-discourse-update/398882/1):
>
> Updating to 2026.3.0-latest has broken my plugin again. Can anyone help explain what is wrong? I see this error in the F12 console in Chrome: app.js:73 Failed to load plugin discourse-directoryopus from https://resource.dopus.com/assets/js/plugins/discourse-directoryopus\_main-iafcdugp.digested.js Error: [PLUGIN discourse-directoryopus] Compile error: RollupError: discourse/plugins/discourse-directoryopus/virtual:entrypoint:main (60:12): Duplicate export "discourse$templates$connectors$user\_\_c…

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [March 20, 2026, 3:19pm UTC](https://meta.discourse.org/t/introducing-a-new-build-system-for-plugins/398713/4 "2026-03-20T15:19:48Z")

</div>

Thanks for the report! Looking into it now 👀

Edit: [fixed](https://meta.discourse.org/t/plugin-duplicate-export-error-after-discourse-update/398882/3)

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [March 26, 2026, 12:06pm UTC](https://meta.discourse.org/t/introducing-a-new-build-system-for-plugins/398713/5 "2026-03-26T12:06:48Z")

</div>

For anyone interested, I’m going to be talking about our new plugin build system at today’s Ember Europe meetup - 2026-03-26T18:00:00Z. It’s a fully remote event - all welcome!

> **[Q1 2026 Event – fully remote, Do., 26. März 2026, 18:45 | Meetup](https://www.meetup.com/ember-europe/events/313431442/)**
>
> Finde Meetup-Events, damit du mehr von dem machen kannst, was dir wichtig ist. Oder erstelle deine eigene Gruppe und treffe Leute in deiner Nähe, die deine Interessen teilen.
