Data Synchronization
Strategies and patterns for keeping data consistent across multiple systems, handling conflicts, and choosing the right sync model for your architecture.
What it is
Data synchronization is the process of ensuring that data in two or more systems remains consistent over time — either by propagating changes from a master to replicas (one-way sync), or by bidirectionally reconciling changes made independently in each system (two-way sync). Synchronization can be triggered by events (a change in System A pushes an update to System B), executed on a schedule (periodic polling and comparison), or applied continuously via a streaming pipeline. The challenge intensifies with bidirectional sync, where both systems can be independently updated, creating the potential for conflicts.
Conflict resolution is the core hard problem of bidirectional sync. Common strategies include: Last-Write-Wins (LWW) — the update with the latest timestamp prevails (simple but lossy, susceptible to clock skew); First-Write-Wins — the first version committed wins and subsequent conflicting updates are rejected; Merge semantics — the system merges non-conflicting fields (updating address fields independently of contact fields); and CRDTs (Conflict-free Replicated Data Types) — specially designed data structures that can always be merged without conflicts (e.g., grow-only counters, OR-Sets).
Why it exists
Modern enterprise architectures routinely duplicate the same logical data across multiple stores: a customer record might live in the CRM (Salesforce), the ERP (SAP), the customer support platform (Zendesk), and the data warehouse. Each system needs the data for different purposes — the CRM for sales workflows, the ERP for billing, the support tool for case context. Rather than creating a single "golden source" that every system queries in real-time (which introduces coupling and latency), synchronization keeps local copies up to date, preserving the autonomy and performance of each system.
Mobile and offline applications add another synchronization dimension: a mobile app works with a local database while offline, then must sync changes back to the server when reconnected, potentially conflicting with changes other users made during the offline period. CouchDB/PouchDB, Realm, and the emerging local-first software movement address this with built-in bidirectional replication protocols.
When to use
- Multiple systems need to work with the same business entity (customer, product, order) and each system performs writes independently.
- Cross-region replication for disaster recovery or latency reduction, where each region serves local writes that must be propagated globally.
- Mobile or offline-first applications that maintain a local database and sync with a server when connectivity is available.
- Microservices that maintain local data replicas for performance (e.g., an order service caches product prices locally and syncs daily).
- Migrating from a legacy system to a new system in parallel, with both running simultaneously while validating data consistency.
- Third-party integrations (Salesforce ↔ HubSpot, Jira ↔ Asana) where both systems are authoritative for different user populations.
When not to use
- If one system can be designated the clear master and all others are strictly read-only replicas, use unidirectional replication (e.g., MySQL replication, DynamoDB global tables in active-passive mode) — it is dramatically simpler.
- If the entities in question require transactional consistency across systems (e.g., inventory deduction must happen atomically with order creation), synchronization via CDC or events is insufficient; use distributed transactions or Saga pattern instead.
- Very high write throughput scenarios where the sync overhead (conflict detection, version comparison) consumes a significant fraction of available compute.
- Entities with complex business rules governing valid state transitions — automated conflict resolution may produce business-invalid states that are hard to detect.
Typical architecture
Bidirectional Sync with Conflict Detection:
┌───────────────────┐ ┌───────────────────┐
│ System A (CRM) │ │ System B (ERP) │
│ Customer record │ │ Customer record │
│ version: v3 │ │ version: v3 │
│ updated_at: T1 │ │ updated_at: T2 │
└────────┬──────────┘ └────────┬──────────┘
│ push change │ push change
▼ ▼
┌──────────────────────────────────────────────────────┐
│ Sync Engine / Event Bus │
│ │
│ ┌────────────────────────────────────────────────┐ │
│ │ Conflict Detection │ │
│ │ - Compare vector clocks / versions │ │
│ │ - Same record modified in both systems? │ │
│ │ - Divergent fields? │ │
│ └────────────────────┬───────────────────────────┘ │
│ │ │
│ ┌────────▼────────┐ │
│ │ Conflict? │ │
│ │ Yes → Apply │ │
│ │ merge strategy │ │
│ │ No → Propagate │ │
│ └─────────────────┘ │
└──────────────────────────────────────────────────────┘
Pros and cons
Pros
- Each system maintains a local copy, providing high availability and low-latency reads without cross-system calls.
- Offline capability: mobile and edge systems can operate independently and sync when connectivity is restored.
- Loose coupling: systems aren't directly dependent on each other's availability for normal operations.
- Enables gradual migration: run old and new systems in parallel with sync while validating the new system.
- CRDT-based sync can provide mathematically guaranteed convergence without centralized coordination.
Cons
- Bidirectional sync is complex to implement correctly; bugs in conflict resolution lead to data loss or corruption.
- Eventual consistency means systems are transiently inconsistent; some use cases cannot tolerate any staleness.
- Last-Write-Wins loses data if two systems make different valid updates to the same field concurrently.
- Schema evolution in either system can break sync mappings; requires coordinated releases.
- Sync lag monitoring and alerting adds operational overhead; undetected sync failures silently diverge systems.
Implementation notes
Use vector clocks or hybrid logical clocks (HLC) rather than wall-clock timestamps for conflict detection when possible — wall clocks on distributed systems can skew significantly, causing LWW to make incorrect decisions. Libraries like hlc.js or jHLC implement HLC in application code. For entity-level sync, track a last_modified_by and last_modified_at on every record, and propagate changes with the source system identifier so the receiving system can detect whether an incoming update supersedes or conflicts with its local version.
For CRM/ERP bidirectional sync, consider designating field-level authority: the CRM is authoritative for marketing fields (email, lead status, campaign attribution); the ERP is authoritative for financial fields (billing address, payment terms, credit limit). Sync logic only allows the authoritative system to overwrite those fields, eliminating most conflicts. Use a sync platform like Boomi, MuleSoft, or Zapier for common SaaS-to-SaaS integrations rather than building bespoke sync engines — these tools have conflict resolution UI, audit trails, and pre-built connectors.
Common failure modes
- Sync loop: System A pushes a change to System B; System B's change triggers a sync back to A; A pushes it back to B — infinite loop consuming resources until the pipeline is shut down.
- Silent data loss via LWW: A user in Europe updates a customer's phone number; simultaneously, a US user updates their email; LWW based on timestamp retains only one update, silently discarding the other.
- Clock skew conflicts: Server A's clock is 5 minutes ahead; LWW consistently favors its changes regardless of actual edit order, systematically overwriting legitimate updates from System B.
- Thundering herd on reconnect: 10,000 mobile clients reconnect after an outage simultaneously; the sync service is overwhelmed by concurrent sync requests and collapses.
- Schema divergence: System A adds a required field that System B's sync adapter doesn't know about; sync silently drops the field, leaving System B with invalid records.
Decision checklist
- Is this unidirectional (simpler) or bidirectional sync? Can you designate a clear master system?
- What is the acceptable staleness window (seconds, minutes, hours)?
- How will you detect and resolve conflicts when both systems modify the same entity concurrently?
- Are there field-level authority rules (one system owns specific fields)?
- How will you prevent sync loops when System B re-publishes changes received from System A?
- Do you have monitoring for sync lag and alerting for sync failures or divergence?
Example use cases
- CRM–ERP customer sync: Salesforce owns lead qualification and marketing data; SAP ERP owns billing and contract data. A sync engine bidirectionally mirrors customer records using field-level authority to prevent conflicts, with a human-review queue for any genuine conflicts.
- Offline mobile field service: Field technicians update work order statuses offline on tablets; when they return to connectivity, the mobile app syncs changes to the server, merging with dispatcher updates using operation-based CRDTs to guarantee convergence.
- Multi-region active-active database: A global SaaS product runs active-active CockroachDB clusters across three regions; the database handles geo-partitioned replication and serializable cross-region transactions, providing data synchronization as a built-in feature.
Related patterns
- Change Data Capture — CDC is a common mechanism for detecting and propagating changes in event-driven sync pipelines.
- Eventual Consistency — The consistency model that bidirectional sync systems typically provide.
- Vector Clocks — The data structure used to track causality and detect conflicts in distributed sync systems.