mongosync

mongosync — MongoDB’s Native Live Migration Tool

mongosync is MongoDB’s official utility for continuous, real-time replication between two MongoDB clusters. It performs a full initial sync followed by change-stream-based CDC (no Kafka, no Debezium) and supports cutover with sub-minute downtime, reverse sync for rollback, and filtered namespace replication. mongosync powers Atlas Live Migration and Cluster-to-Cluster Sync.

1. Architecture — Initial Sync + Ongoing CDC

mongosync runs as a standalone Go binary outside of mongod/mongos. It opens connections to two clusters and moves data in two phases:

  1. Initial sync — mongosync reads collection data from the source cluster in parallel workers, applies inserts to the destination cluster, builds indexes, and tracks progress per-collection.
  2. Change Event Application (CEA) — once initial sync completes, mongosync tails the source via change streams, applies operations to the destination, and stays in lockstep until you commit or pause. mongosync does not read the oplog directly — it relies on the change-streams API.

Because CDC runs over change streams, mongosync’s resumability depends on the source oplog window. If un-applied operations age out of the source oplog, the change stream returns ChangeStreamHistoryLost and mongosync fails — see Section 6.

Topology notes

Migration host sizing

For a production sync, MongoDB recommends a dedicated migration host with at least 8 CPUs and 24 GB of RAM. The host needs network reachability to both clusters and enough disk for logs and the local progress state.

2. Configuration

CLI vs config file

mongosync accepts CLI flags or a YAML/JSON config file via --config. The config file is the production-grade path because:

Core connection options

Option Purpose
--cluster0 Connection URI for the first cluster (source or destination).
--cluster1 Connection URI for the second cluster (source or destination).
--config Path to YAML/JSON config file. Preferred for secrets.
--logPath Directory where mongosync writes log files.
--loadLevel Aggressiveness 1–4. Default 3. Higher = faster + more destination load.
--verbosity Log verbosity (TRACE, DEBUG, INFO, WARN, ERROR, FATAL).

Cluster role (source vs destination) is not set on the binary — it’s decided by the call to the /api/v1/start endpoint. The same mongosync process can be reversed; see Section 8.

Example minimal config (YAML)

cluster0: "mongodb+srv://migrator:<password>@source.example.com/?authSource=admin"
cluster1: "mongodb+srv://migrator:<password>@dest.example.com/?authSource=admin"
logPath: "/var/log/mongosync"
loadLevel: 3
verbosity: "INFO"
port: 27182

REST API surface

mongosync exposes an HTTP API on 127.0.0.1:27182 (default port). Key endpoints:

Endpoint Purpose
POST /api/v1/start Begin the sync. Body specifies source, destination, filters, options.
GET /api/v1/progress Current state, copy phase progress, lag, errors.
POST /api/v1/pause Pause sync (entering PAUSED).
POST /api/v1/resume Resume from PAUSED. Can take ~2 minutes before transitioning.
POST /api/v1/commit Begin cutover (COMMITTING → COMMITTED).
POST /api/v1/reverse Reverse sync direction (requires reversible:true at start).

start body — the essential fields

{
  "source": "cluster0",
  "destination": "cluster1",
  "reversible": true,
  "enableUserWriteBlocking": true,
  "includeNamespaces": [
    { "database": "sales", "collections": ["EMEA", "APAC"] },
    { "database": "marketing" }
  ]
}

3. Filtering — includeNamespaces / excludeNamespaces / namespace remap

Basic filters

includeNamespaces and excludeNamespaces are mutually exclusive arrays of filter objects. Each object has a database and optionally a collections array. With no filter mongosync performs a full cluster sync (every non-system database/collection).

"includeNamespaces": [
  { "database": "sales", "collections": ["EMEA", "APAC"] },
  { "database": "marketing" }
]

This includes only sales.EMEA, sales.APAC, and every collection under marketing.

Regex filters (mongosync 1.6+)

Filter values can be regular expressions, so you can match many databases/collections at once:

"includeNamespaces": [
  { "database": "/^tenant_[0-9]+$/", "collections": ["/^orders.*/"] }
]

Namespace remapping

namespaceRemap lets you rewrite the destination namespace, useful for tenant consolidation or rename-during-migration. The destination database and/or collection name can differ from the source.

Filter immutability

You cannot change a filter on a running sync. Stop mongosync, prepare the destination (drop any partially-synced collections), and start a new sync with the updated filter. There is no in-place filter edit.

Items mongosync never replicates

4. Resumability — Checkpoint State and Resume

Where state lives

mongosync writes progress and resume tokens to the destination cluster (in a metadata collection mongosync owns). That is why resume after a process crash works even on a brand-new mongosync host: the durable checkpoint lives next to the data.

Resume rules

When you cannot resume

5. Verification

mongosync ships four verification methods. Pick based on cluster shape and downtime budget.

5.1 Embedded verifier (default, replica sets)

5.2 Hash comparison (dbHash MD5)

5.3 Document counts

5.4 Migration Verifier (mongodb-labs/migration-verifier)

Verification decision tree

sharded cluster?           → migration-verifier
replica set, low-mutation? → embedded verifier (default) is enough
need cryptographic proof?  → dbHash, but pause writes first
insert-only data?          → document counts

6. Failure Modes & Troubleshooting

Oplog window exhaustion

Symptom: mongosync exits with ChangeStreamHistoryLost or similar — the source oplog rolled past mongosync’s resume point.

Causes:

Fixes:

Rule of thumb: set minRetentionHours to 2–3× the expected initial-sync duration plus any pause window.

Network partitions

mongosync retries transient network errors with exponential backoff. Sustained partitions cause mongosync to surface errors via /progress and eventually stop. Restart picks up from the last checkpoint iff the oplog window is still intact.

Schema drift

mongosync replicates DDL via change events — collection creates, drops, index builds. It does not repair manual drift on the destination. If someone writes directly to the destination while a sync runs, you’ve corrupted the migration; restart from scratch. enableUserWriteBlocking on the destination is the guardrail.

Stalled progress

Cannot reverse / reverse refused

7. mongosync vs Atlas Live Migration vs Cluster-to-Cluster Sync

All three use the same underlying mongosync engine. The difference is the operating envelope:

Tool Best for Manages host? Filters? Network
Atlas Live Migration (pull) ≤5 TB, ≤3 shards, into Atlas Yes — Atlas provisions migration servers No filtering, full cluster Public network only — no VPC peering, no private link
Atlas Live Migration (push) Cloud Manager / Ops Manager source Yes — Atlas drives Ops Manager agents No filtering Public + Cloud/Ops Manager visibility
Standalone mongosync Any size, filtered sync, private networking, version cross No — you operate the host Full include/exclude/regex Any (VPC peering, private link)
Cluster-to-Cluster Sync (MongoDB 7.0+) Continuous sync between two clusters (DR, multi-cloud) No Yes Any

Decision rules

8. Reverse Sync — Cutover & Rollback

Cutover process

  1. mongosync is RUNNING with lagTimeSeconds low (sub-second on healthy networks).
  2. Quiesce application writes on the source.
  3. Call POST /api/v1/commit.
  4. mongosync moves to COMMITTING — drains remaining change events.
  5. mongosync reaches COMMITTED — final state. The destination is now authoritative.
  6. Flip application connection strings to the destination cluster.

Healthy production cutovers complete in under 60 seconds because mongosync already had CDC caught up before commit.

Reverse sync — rollback

If the destination misbehaves post-cutover, you can flip the direction:

POST /api/v1/reverse

This requires:

After reverse, the original destination becomes source, and writes on the new source flow back to the original source. Filtered Sync is not supported during reverse — reverse syncs the full cluster.

State machine summary

   IDLE ──start──▶ RUNNING ──pause──▶ PAUSED ──resume──▶ RUNNING
                       │                    │
                       │ commit             │ (auto from RUNNING/PAUSED)

                  COMMITTING ──(auto)──▶ COMMITTED

                       │ reverse (only with reversible=true)

                  REVERSING ──(auto)──▶ RUNNING (reverse direction)

State transitions are mostly API-driven; COMMITTING→COMMITTED and REVERSING→RUNNING are automatic.

9. Performance Tuning

loadLevel

One mongosync per shard

For sharded sources, run one mongosync instance per shard for true parallel copy. Coordinate them so they share the destination cluster’s URI.

Index builds

Balancer

Disable the balancer on the sharded destination (sh.stopBalancer() / balancerStop) before starting the migration. The balancer fighting with mongosync inflates the migration window and can cause chunk-move-vs-CDC races.

Other tuning knobs

10. Security — TLS & x.509

mongosync inherits MongoDB’s standard auth. For production:

TLS

Required roles

The mongosync user on each cluster needs broad read/write across the synced namespaces plus:

Atlas exposes a built-in role specifically for mongosync (Atlas Admin is sufficient but overpowered — use the documented minimal role set).

Network security

Quick-reference checklist for a new mongosync migration

Pre-flight:

Configuration:

Operate:

Cutover:

Sources