Faster Builds in Meteor 3.3: Modern Build Stack with SWC and Bundler Optimizations

Meteor 3.3 slashes build times by around 60% on average, with some projects building over 3× faster builds. We’ve upgraded the Galaxy Cloud app, and the cloud team’s development and delivery experience has already improved thanks to these gains.

This is the first major update to the Meteor bundler in years, introducing several optimizations. The main change is switching from Babel to SWC for transpiling and minifying to speed up builds.

This release also includes community contributions for Meteor React packages, improving stability and performance of common hooks and adding support for React 19.

Hands on

To start using Meteor 3.3.

Update Your App

# Update your existing Meteor app to version 3.3
meteor update --release 3.3

Create a New App

# Create a new Meteor app using Meteor 3.3
meteor create my-app --release 3.3

Add this to your package.json to enable the new modern build stack:

"meteor": {
  "modern": true
}

This setting is on by default for new apps.

Check the docs for help with the SWC migration, especially if your project uses many Babel plugins.

:link: Modern Transpiler: SWC docs

If you find any issues, please report them to the Meteor issues tracker.


For full details on what’s included in Meteor 3.3, see the changelog.

Check out our latest post for the highlights of this release.

For more insights into the release, watch the release video.

Big up contributors

We want to highlight how important community members contributions have been in delivering these changes.

Thanks to our core contributors: @nachocodoner, @italojs, @Grubba27, @zodern, @9Morello, @welkinwong, @Poyoman39, @PedroMarianoAlmeida, @harryadel, @ericm546, @StorytellerCZ.

Thanks to community members for testing and feedback on Meteor 3.3: @zodern, @minhna, @paulishca, @pmogollon, @ferjep, @wreiske, @schlaegerz.

What’s Next?

For the upcoming releases, we have the following priorities.

  • Stability and patches. Collect feedback, fix missing support or issues in modern build stack, and ship pending contributions. Planned Meteor 3.3.x patches.

  • Modern bundler. Integrate a bundler that meets current standards for performance, tooling, plugin support, and community growth. Planned for Meteor 3.4. A demonstration is available, please share your feedback on the Meteor-RSPack integration.

  • Change streams. Provide a unified API for MongoDB change notifications to improve efficiency and consistency. Research is underway, please share your feedback: MongoDB Change Streams support in Meteor.

6 Likes

That’s what I call an awesome release. Congrats on the work, guys.

And a huge thank you to this amazing community that makes it all possible :slight_smile:

3 Likes

What are the future of Babel plugins? Right now they are mentioned as “backwards compatible” which sounds to me that they get dropped in a future release?

I ask because right now the only way I know to get decent code coverage for meteortesting:mocha is to use lmieulet:meteor-coverage which uses babel-plugin-istanbul. Do I already need to plan a rewrite soon?

1 Like

After updating to 3.3, no babel configurations or plugins work, which doesn’t let us compile.

I see the move to SWC, but is there any guide on how to migrate everything manually?

1 Like

I don’t think we’ll drop Babel entirely, it’s deeply embedded in Meteor core and many packages still depend on it. Even with SWC as the default in modern bundlers, Babel remains a valid, opt-in choice for its mature ecosystem.

For those who want to move fully to SWC, we’ll need to adapt the Meteor tools that rely on Babel or provide a SWC alternative. For example, there’s the swc-plugin-coverage-instrument, though I’m not sure how much work is needed to make it run on the meteor-coverage package. Testing in general needs modernization. It would be great to address this at some point.

1 Like

We have added documentation to explain the migration process and the verifications behind it.

Try the verbose option documented and, if you see any errors, report them in an issue, including the Babel plugins you’re using, and any other additional context. Please report an issue on the Meteor issue tracker.

We’d like to support more setups. Even after several betas and RC, some specific setups may still require specific migrations. If SWC doesn’t work for you, you can keep using Babel by disabling the modern setting (it should fall back automatically unless there’s an unknown side effect). We appreciate your feedback to improve compatibility.

2 Likes

I must be doing something wrong – I’m getting no speedup yet with 3.3. I’ve:

  • run meteor update --release 3.3
  • run meteor reset
  • tried “meteor”: {
    “modern”: true
    } at the top level of both package.json and settings.json

…but have seen no speedup yet.

…wait, I’ve got a couple of babel dependencies. That must be it. I’ll try that and report back.

[LATER] No, I’m still not seeing faster builds yet.

In my METEOR_PROFILE printout, I see a lot of dependencies on Babel. Could this be what’s preventing the speedup?

METEOR 3.3 PROFILE (edited to just show babel dependencies)

| (#1) Profiling: Server startup
|
| Server startup…6,966 ms (1)
| ├─ Load server bundles…6,881 ms (1)
| │ ├─ packages/react-fast-refresh.js…12 ms (1) [Uses Babel]
| │ │ └─ require(“/node_modules/meteor/react-fast-refresh/server.js”).12 ms (1)
| │ │ ├─ require(“semver/functions/gte”) 6 ms (1)
| │ │ ├─ require(“react-refresh/babel”) 5 ms (1) [Babel Dependency]
| │ │ └─ other require(“/node_modules/meteor/react-fast-refresh/server.js”) 1 ms
| │ ├─ packages/babel-runtime.js…1 ms (1) [Uses Babel]
| │ ├─ packages/minimongo.js…17 ms (1) [Babel Dependency]
| │ │ └─ require(“/node_modules/meteor/minimongo/minimongo_server.js”).17 ms (1)
| │ │ └─ require(“/node_modules/meteor/minimongo/minimongo_common.js”).16 ms (1)
| │ │ ├─ require(“/node_modules/meteor/minimongo/local_collection.js”).13 ms (1)
| │ │ │ ├─ require(“/node_modules/@babel/runtime/helpers/objectSpread2.js”) 5 ms (1) [Babel Dependency]
| │ │ │ ├─ require(“/node_modules/meteor/minimongo/cursor.js”).4 ms (1)
| │ │ │ │ ├─ require(“/node_modules/meteor/minimongo/common.js”) 2 ms (1)
| │ │ │ │ └─ other require(“/node_modules/meteor/minimongo/cursor.js”) 2 ms
| │ │ │ └─ other require(“/node_modules/meteor/minimongo/local_collection.js”) 3 ms
| │ │ ├─ require(“/node_modules/meteor/minimongo/matcher.js”) 1 ms (1)
| │ │ └─ other require(“/node_modules/meteor/minimongo/minimongo_common.js”) 1 ms
| │ ├─ packages/ddp-client.js…19 ms (1) [Babel Dependency]
| │ │ └─ require(“/node_modules/meteor/ddp-client/server/server.js”).19 ms (1)
| │ │ └─ require(“/node_modules/meteor/ddp-client/common/namespace.js”).18 ms (1)
| │ │ ├─ require(“/node_modules/meteor/ddp-client/common/livedata_connection.js”).16 ms (1)
| │ │ │ ├─ require(“/node_modules/@babel/runtime/helpers/objectWithoutProperties.js”) 2 ms (1) [Babel Dependency]
| │ │ │ ├─ require(“/node_modules/meteor/ddp-client/common/connection_stream_handlers.js”) 1 ms (1)
| │ │ │ ├─ require(“/node_modules/meteor/ddp-client/common/message_processors.js”) 3 ms (1)
| │ │ │ ├─ require(“/node_modules/meteor/ddp-client/common/document_processors.js”) 2 ms (1)
| │ │ │ └─ other require(“/node_modules/meteor/ddp-client/common/livedata_connection.js”) 6 ms
| │ │ └─ other require(“/node_modules/meteor/ddp-client/common/namespace.js”) 2 ms
| │ ├─ packages/babel-compiler.js…154 ms (1) [Uses Babel]
| │ │ ├─ Npm.require(“semver”) 29 ms (1)
| │ │ ├─ Npm.require(“json5”) 4 ms (1)
| │ │ ├─ Npm.require(“@meteorjs/swc-core”) 12 ms (1)
| │ │ ├─ Npm.require(“@meteorjs/reify/lib/compiler”) 101 ms (1)
| │ │ └─ other packages/babel-compiler.js 4 ms
| │ ├─ packages/logging.js…9 ms (1) [Babel Dependency]
| │ │ └─ require(“/node_modules/meteor/logging/logging.js”)…8 ms (1)
| │ │ ├─ require(“/node_modules/meteor/logging/node_modules/@babel/runtime/helpers/objectSpread2.js”) 7 ms (1) [Babel Dependency]
| │ │ └─ other require(“/node_modules/meteor/logging/logging.js”) 2 ms
| │ ├─ require(“/node_modules/meteor/mongo/mongo_driver.js”)…30 ms (1) [Babel Dependency]
| │ │ ├─ require(“/node_modules/meteor/mongo/oplog_tailing.ts”)…29 ms (1)
| │ │ │ ├─ require(“/node_modules/meteor/mongo/node_modules/lodash.isempty/index.js”) 2 ms (1)
| │ │ │ ├─ require(“/node_modules/meteor/mongo/mongo_connection.js”).24 ms (1)
| │ │ │ │ ├─ require(“/node_modules/meteor/mongo/asynchronous_cursor.js”).5 ms (1)
| │ │ │ │ │ ├─ require(“/node_modules/meteor/mongo/mongo_common.js”).4 ms (1)
| │ │ │ │ │ │ ├─ require(“/node_modules/meteor/mongo/node_modules/lodash.clone/index.js”) 3 ms (1)
| │ │ │ │ │ │ └─ other require(“/node_modules/meteor/mongo/mongo_common.js”) 1 ms
| │ │ │ │ │ └─ other require(“/node_modules/meteor/mongo/asynchronous_cursor.js”) 1 ms
| │ │ │ │ ├─ require(“/node_modules/meteor/mongo/cursor.ts”) 2 ms (1)
| │ │ │ │ ├─ require(“/node_modules/meteor/mongo/oplog_observe_driver.js”).8 ms (1)
| │ │ │ │ │ ├─ require(“/node_modules/@babel/runtime/helpers/asyncIterator.js”) 1 ms (1) [Babel Dependency]
| │ │ │ │ │ ├─ require(“/node_modules/meteor/mongo/node_modules/lodash.has/index.js”) 2 ms (1)
| │ │ │ │ │ └─ other require(“/node_modules/meteor/mongo/oplog_observe_driver.js”) 4 ms
| │ │ │ │ ├─ require(“/node_modules/meteor/mongo/polling_observe_driver.ts”) 2 ms (1)
| │ │ │ │ └─ other require(“/node_modules/meteor/mongo/mongo_connection.js”) 5 ms
| │ │ │ └─ other require(“/node_modules/meteor/mongo/oplog_tailing.ts”) 2 ms
| │ │ └─ other require(“/node_modules/meteor/mongo/mongo_driver.js”) 2 ms
| │ └─ other Load server bundles 1,687 ms
| ├─ Call Meteor.startup hooks…73 ms (1)
| └─ Run main() 13 ms (1)
|
| Top leaves:
| other Load server bundles…1,687 ms (1)
| Npm.require(“@meteorjs/reify/lib/compiler”)…101 ms (1)
|
| (#1) Total: 6,966 ms (Server startup)

Just to double-check, where did you add your "modern": true config? It needs to go in your app project’s package.json file (no settings.json). Also, make sure it isn’t already there, most Meteor apps already include the Meteor config with mainModule and testModule settings.

I attach an example of package.json config:

image

Also, to understand if SWC or Babel is used you should activate the verbose mode, adding modern like:

"meteor": {
  "modern": {
    "transpiler": {
      "verbose": true
    }
  }
}

I’ll send you a DM to help enable your SWC, and you can forward me the verbose logs so I can verify everything is set up correctly.

Edit:

The “Server startup” log you provided doesn’t prove SWC isn’t used, since SWC runs at build time and the startup phase is runtime, where Babel may still be in use. Instead, the “Build App” phase can be used to confirm SWC is enabled.

Do we still need modernWebArchsOnly and modernTranspiler in our package.json file?

like here:

"meteor": {
    "modern": true,
    "modernWebArchsOnly": true,
    "modernTranspiler": true,
    "mainModule": {
      "client": "client/main.js",
      "server": "server/main.js"
    }
  },

Also running the app with --exclude-archs web.browser.legacy. When I run it, I get this warning:

modern.webArchOnly and --exclude-archs are both active. If both are set, --exclude-archs takes priority.

Thanks in advance, congrats to the team on this milestone,

Andreas

modernTranspiler and modernWebArchsOnly are no longer needed. They were added in the first beta, but in the next beta we replaced them with a single modern field that activates all context optimizations by default. You can opt out of each one within modern.

Please check the docs and each component’s section for more details.

Also running the app with --exclude-archs web.browser.legacy . When I run it, I get this warning:

The warning is harmless. It just means that enabling “modern” already applies “exclude-archs,” so you don’t need to include it.

Thanks @nachocodoner . I’ll reply on the DM.