DEV Community

Cover image for Why Meteor 3.5 Is the Most Important Release in Years
Meteor Software
Meteor Software

Posted on

Why Meteor 3.5 Is the Most Important Release in Years

Every framework has a handful of releases that actually change its trajectory. For Meteor, 3.0 was one of them: it removed Fibers and rebuilt the framework on native async/await.

Meteor 3.5, released on June 30, 2026, is the next one. Not because of the length of its changelog, but because of a single line in it: MongoDB Change Streams are now the default reactivity mechanism.

To understand why that matters, you need to understand what it replaces.

A decade of oplog tailing
Meteor’s signature feature has always been real-time reactivity: you write a publication, the client subscribes, and the UI updates when the data changes. No sockets to manage, no invalidation logic to write. Since around 2014, the engine behind that magic has been oplog tailing.

The oplog is MongoDB’s internal replication log — a record of every write that happens in the database. Meteor’s oplog driver tails that log and diffs each change against the queries your app is observing, deciding which clients need to hear about it.

It worked, and it worked for a decade. But the architecture carries a structural cost: the oplog records everything. Every insert, update, and delete in the entire database flows through it — whether your app’s publications care about those documents or not. A busy background collection, a bulk import, a logging table with millions of writes per day: your Meteor app had to process all of it just to find the changes that mattered.

At small scale, that’s invisible. At high scale, it becomes the bottleneck that defined Meteor’s performance ceiling. As traffic grows, the diffing work accumulates faster than the server can deliver results, a backlog builds, and the process eventually dies with an Out of Memory crash. If you’ve operated a large Meteor app, you’ve probably met this failure mode personally.

What Change Streams do differently
MongoDB Change Streams invert the model. Instead of consuming the entire firehose and filtering it locally, the driver asks MongoDB to watch a specific collection with a specific query — and MongoDB pushes back only the changes that match.

The difference is easy to see in a publication:

Meteor.publish('links', function () {
// With Change Streams, Meteor watches ONLY LinksCollection,
// and ONLY documents matching this query.
return LinksCollection.find({ my: 'query' });
});
Meteor.publish('links', function () {
  // With Change Streams, Meteor watches ONLY LinksCollection,
  // and ONLY documents matching this query.
  return LinksCollection.find({ my: 'query' });
});
Enter fullscreen mode Exit fullscreen mode

Under oplog, this publication forced the server to observe every write in the database. Under Change Streams, the filtering happens inside MongoDB, and the data is processed as a stream rather than accumulated locally. Your busiest collection can churn all day; if no publication observes it, your app never hears about it.

The application code is identical. That’s the point: this is an engine swap, not an API change.

The numbers
The Meteor team benchmarked both drivers with a standard Meteor app under high-frequency writes, running on a Galaxy container with 8 vCPUs and 8 GB of RAM, load-tested with Artillery.

The oplog driver saturated at 1,200 virtual users. Past that point, persistent timeouts piled up until the process crashed with an Out of Memory error, the classic oplog failure mode, reproduced on demand.

The Change Streams driver handled 1,680 virtual users — a 40% increase in connection capacity. And the more important result is what happened beyond that point: nothing fatal. Under extreme stress, the system produced timeouts, but the process stayed up. The failure mode changed from a crash to graceful degradation.

For teams running production Meteor apps, that second result is arguably worth more than the 40%. Capacity limits can be planned around; OOM crashes at peak traffic cannot.

There’s a cost dimension too. If each app server sustains more concurrent users, subscriptions, and method calls, the same workload needs fewer containers. The performance improvement is also an infrastructure bill improvement.

The bonus nobody should overlook
Oplog tailing had a hard requirement: access to MongoDB’s replication log. Managed and serverless MongoDB tiers (Atlas Shared, serverless instances) don’t expose it. Apps on those tiers were forced into polling, the slowest and most expensive reactivity mode.

Change Streams are a public, supported MongoDB API. They work on managed tiers. With 3.5, real-time reactivity reaches a whole class of deployments that never had it, which lowers the barrier for small apps and side projects that start on shared database tiers.

What upgrading looks like
For most apps, the upgrade is one command:

meteor update --release 3.5
Enter fullscreen mode Exit fullscreen mode

Change Streams are enabled by default, with two things worth knowing:

The requirement: Change Streams need MongoDB 6+ running as a replica set or sharded cluster. On older setups, Meteor automatically falls back to oplog or polling — nothing breaks, you just don’t get the new driver.

The escape hatch: if you need the previous behavior, reactivity is configurable in settings.json, and Meteor tries each driver in order:

{
  "packages": {
    "mongo": {
      "reactivity": ["changeStreams", "oplog", "polling"]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Set it to ["oplog", "polling"] to opt out entirely. A default you can reverse with one line is the right way to ship a change this deep.

The rest of 3.5
Change Streams headline the release, but 3.5 is dense. DDP Session Resumption means short disconnects — mobile handoffs, sleeping tabs, load balancer timeouts — resume the existing session within a grace period instead of triggering a full re-subscribe cycle, cutting reconnect-storm CPU spikes.

A new pluggable DDP transport layer lets you swap SockJS for uWebSockets with a single flag for lower latency on controlled deployments.

The new accounts-express package makes authenticated REST endpoints first-class citizens, with Meteor.userId() available in Express routes.

And the runtime moves to Node.js 24 LTS, alongside a batch of EJSON serialization optimizations.

Any one of these would carry a normal release. In 3.5, they’re the supporting cast.

Why this release matters more than a version number suggests
Frameworks age in two ways: their APIs age, and their assumptions age. Meteor 3.0 fixed the aging API by removing Fibers. Meteor 3.5 fixes the aging assumption — that real-time reactivity requires tailing a replication log that was never designed to be an application-facing interface.

Oplog tailing was a brilliant hack that lasted ten years. Change Streams are the supported, scalable primitive that MongoDB built for exactly this job. With 3.5, Meteor’s most distinctive feature finally runs on infrastructure designed for it — with measurably higher capacity, a safer failure mode, and zero changes to application code.

If you run Meteor in production, this is the upgrade to prioritize. And if you left Meteor years ago because of oplog scaling stories, 3.5 is the release that retires them.

Galaxy is the cloud platform built by the team behind Meteor. Apps on Galaxy get zero-downtime deploys, Autoscaling, and managed MongoDB running next to your app: the same infrastructure the Meteor 3.5 benchmarks ran on. Deploy your Meteor 3.5 app today.

Top comments (1)

Collapse
 
frank_signorini profile image
Frank

I'm curious if 3.5 introduces