MongoDB Realm Sync, or more accurately, MongoDB Atlas Device Sync, is the engine that lets your mobile apps work offline and then seamlessly sync data with your MongoDB Atlas backend when a connection is available.

Imagine you’re building a field service app. Your technicians need to log work orders, update customer details, and mark tasks complete, even if they’re in a basement with no signal. Device Sync makes this possible by keeping a local copy of the data on their device, allowing them to work uninterrupted. When they’re back online, Device Sync intelligently merges their local changes with any changes that happened on the server or other devices, all without you having to write complex conflict resolution logic.

Here’s a simplified look at how it works under the hood, focusing on the core components and flow:

1. Local Data Storage: On the device, Realm SDKs (for Swift, Kotlin, JavaScript, etc.) manage a local, embedded, encrypted database. This is where your app’s data lives when offline. It’s not just a simple file; it’s a fully functional Realm database.

2. The Sync Engine: This is the magic. It’s a component within the Realm SDK that constantly monitors changes to the local Realm. When a change occurs (a new record added, an existing one updated, or deleted), the sync engine records it.

3. Connection and Authentication: When the device has an internet connection, the sync engine establishes a secure connection to your MongoDB Atlas cluster. This connection uses WebSocket for real-time communication. Authentication is typically handled via MongoDB App Services (now part of Atlas Device Sync), using mechanisms like email/password, custom JWT, or OAuth providers.

4. Data Synchronization: Once connected and authenticated, the sync engine begins sending local changes to Atlas. Simultaneously, it listens for changes coming from Atlas (originating from other devices or the server-side).

  • Upload: Local changes are batched and sent to Atlas.
  • Download: Changes from Atlas are received and applied to the local Realm.

5. Conflict Resolution: This is where Device Sync truly shines. If the same piece of data is modified on two different devices while offline, and then both devices come back online, a conflict arises. Device Sync, by default, uses a "last-write-wins" strategy. The change that was committed last (either locally or on the server) takes precedence. This is configurable, allowing for more complex strategies if needed.

Let’s see a bit of code in action. This is a simplified example using the JavaScript SDK, showing how you might open a synced Realm.

// Assuming you have initialized the Atlas App Services SDK
const app = new Realm.App({ id: "your-app-id" });

async function loginAndOpenRealm() {
  // Authenticate a user (e.g., anonymous authentication)
  const credentials = Realm.Credentials.anonymous();
  const user = await app.logIn(credentials);

  // Define your synced Realm configuration
  const realmConfig = {
    sync: {
      user: user,
      partitionValue: "my_partition_key", // Or null for flexible sync
      // For flexible sync, you'd define your query-based subscriptions here
    },
  };

  // Open the synced Realm
  const syncedRealm = await Realm.open(realmConfig);

  console.log("Successfully opened synced Realm!");

  // Now you can interact with syncedRealm like any other Realm
  syncedRealm.write(() => {
    syncedRealm.create("Task", { _id: new ObjectId(), description: "Learn Device Sync", status: "Open" });
  });

  // Listen for changes
  syncedRealm.addListener("change", (newRealm, changes) => {
    console.log("Realm changed:", changes);
  });

  return syncedRealm;
}

loginAndOpenRealm().catch(console.error);

In this snippet:

  • Realm.App({ id: "your-app-id" }) connects to your Atlas App Services application.
  • Realm.Credentials.anonymous() shows a simple authentication method.
  • sync: { user: user, partitionValue: "my_partition_key" } is the key part for traditional partition-based sync. partitionValue dictates which data this Realm instance is allowed to see and sync. All objects with the same partitionValue are grouped together and synced.
  • For modern, flexible sync, you wouldn’t use partitionValue. Instead, you’d define sync: { user: user, ... } and then use syncedRealm.subscriptions.update(...) to define queryable collections that the client should sync.

The most surprising and often misunderstood aspect of Device Sync is its handling of data modeling and schema. While you define your Realm schema on the client, Device Sync itself doesn’t enforce a strict server-side schema in the same way a traditional MongoDB database does by default. Instead, the schema is derived from the data that flows through the sync process. If you introduce a new field on one client, and that data syncs, the server adapts to accommodate it. This flexibility is powerful for rapid mobile development but requires careful consideration for data consistency across different clients and potential server-side integrations. You can enforce schema validation within Atlas itself, but Device Sync’s initial behavior is to be schema-flexible on the wire.

The next step after getting basic sync working is understanding how to manage complex data relationships and offline-first architectural patterns that leverage this synchronization capability.

Want structured learning?

Take the full Mongodb course →