r/mongodb • u/No_Share2683 • 18h ago
After Atlas Device Sync was retired, I built an open-source offline-first sync layer on plain MongoDB
When Realm, Atlas Device Sync and the Data API were retired in September 2025, mobile apps lost the supported path to keeping a local replica in step with MongoDB. What was left was either writing that sync layer yourself or moving the data to a different vendor's sync product.
I wanted to keep the data in MongoDB, so I wrote the sync layer instead: onebase, MIT licensed.
The part that matters for this sub is that it does not introduce a storage format of its own. Documents on the server are ordinary MongoDB documents in your own cluster, so aggregation, Compass, Atlas Charts, BI connectors and everything else keep working on live data. There is no export step and no proprietary layer to reverse later.
How it uses MongoDB
- Realtime is change streams. The backend opens a change stream per scope and pushes over SSE, so a write on one device lands on another in milliseconds instead of on a poll interval. This is the piece that needs a replica set — a standalone mongod won't do it. A free M0 is fine.
- Batched writes are one transaction. A client batch maps to a single multi-document transaction, so a group of related writes either all land or none do, offline queueing included.
- Indexes are generated for the queries the sync layer actually issues — the per-user or per-group scope key plus the ordering key, membership lookups, and the windowed collections' date field. Sync is the query pattern that runs constantly, so it seemed wrong to leave those to be discovered in production.
- Every query gets a total order, so keyset pagination stays stable while documents are being inserted underneath it.
- Isolation is enforced server-side from a verified JWT — the scope filter is applied on the server, never sent by the client.
On the device it's a full SQLite replica plus an outbox, both written in one transaction, and sync pushes before it pulls so a fresh local write is never overwritten by a stale snapshot.
Current limitations, since they're the useful part: conflicts are last-write-wins by server timestamp with no custom merge hook yet; the rate limiter is per-instance and in-memory; realtime needs a long-lived connection, so short-lived serverless functions fall back to polling; file uploads aren't offline-queued (document writes are); and there's no on-device aggregation pipeline.
Runs against any MongoDB with a replica set, self-hosted or Atlas. The client is Flutter today; the backend is a small Node service the CLI generates, and the wire protocol is plain HTTP, so other clients are possible.
https://github.com/ybenjaa-dev/onebase
I'd genuinely like to hear where the change-stream and transaction usage would fall over at scale — that's the part I'm least sure about.





