Home / Cosmos DB / Engineer Course
V12
🌍
Lesson · 6 min

Global Distribution

Multi-region writes, conflict resolution, and the trade-offs of going global.

TL;DR

Adding a region in Cosmos is a checkbox. Reads from the nearest region happen automatically. Multi-region writes turn the cluster into a multi-master — a feature very few databases offer turnkey, with the trade-off that you can't have strong consistency globally. Conflicts resolve by last-write-wins or a custom merge function you supply.

Key takeaways
  • Single-region write + many read regions — the safe default. Fast reads everywhere, all writes through one region, no conflicts.
  • Multi-region writes — every region accepts writes. Trade-off — strong consistency disabled (must use bounded staleness or weaker), conflicts possible.
  • Conflict resolution — last-write-wins by timestamp (default) or custom merge stored procedure.
  • Failover — automatic in case of regional outage. Manual failover is also a button click.
  • Cosmos charges by GB-stored *per region*. Five regions = 5× storage cost. Reads scale with the closest region; writes go to the closest writable region.

This is one of Cosmos’s signature features — adding a region is genuinely a checkbox in the portal. The first time you do it, the words “globally distributed” stop being a marketing phrase and become something your app actually runs on.

Two distribution modes

Single-region write, multi-region read — one region accepts writes; all other regions are read replicas. Reads happen locally everywhere, writes incur cross-region latency for users far from the write region. Strong consistency is allowed in this mode (lesson V04). This is the safe default.

Multi-region write (multi-master) — every region accepts both reads and writes. Local latency on everything, everywhere. Strong consistency is disabled — the maximum is bounded staleness. Conflict resolution becomes part of your data model.

How the SDK routes

You configure preferred regions on the client:

new CosmosClientOptions {
  ApplicationPreferredRegions = new[] { Regions.WestUS2, Regions.EastUS },
}

For reads — the SDK tries the first region; on failure or unavailability, falls through. For writes (in multi-master) — same logic. For writes (in single-master) — the SDK looks up the current write region from a metadata cache and routes there, regardless of preferences.

Conflict resolution

This only matters in multi-master. Two regions write to the same document at the same time — what happens?

Last-write-wins (default)

Cosmos compares server-generated timestamps. The later write wins; the earlier one is moved to a conflict feed container where you can inspect or merge it later. This is correct for most cases — overlapping writes on the same field are rare in practice.

Custom merge

You provide a stored procedure that runs server-side after a conflict is detected. Receives both versions; returns the merged result.

function resolveConflict(incomingDoc, existingDoc) {
  // domain-aware merge — e.g. shopping cart union
  return { ...existingDoc, items: union(existingDoc.items, incomingDoc.items) };
}

Use custom merge when LWW would cause real data loss — collaborative documents, multi-region shopping carts, anything where “later writer wins” is wrong.

Failover

Two flavors:

Automatic failover (account setting) — if Cosmos detects a regional outage, the write region shifts to the next-priority region within seconds. Your app sees a few seconds of write failures, then resumes. No code change required if your PreferredRegions includes the failover target.

Manual failover — you click a button (or call an ARM API) to promote a region. Useful for testing your DR runbook, planned maintenance, or moving the write region for performance reasons.

Failover is on by default in modern accounts. Test it — pick a region, click “Failover,” watch your app continue. The first time you do this in staging is a confidence-boosting moment.

The cost

Storage — each region holds a full replica. 5 regions × 50 GB = 250 GB of storage cost.

Throughput — provisioned RU/s is per region. 1000 RU/s globally = 1000 in each of 3 regions = 3000 RU/s billed. Cosmos sells “Reserved RU/s” discounts for committed multi-region usage.

Egress — cross-region data transfer (replication) is included free in the same Azure account, but if you’re feeding Change Feed to another region, that transfer is billed.

When to add regions

In rough priority order:

  1. Latency — your users span continents. Adding a region near them cuts read latency from 200ms to 20ms.
  2. Disaster recovery — a second region as a hot standby. Even if traffic doesn’t go there, it’s a tested DR target.
  3. Compliance — data sovereignty rules require data to live in specific regions.
  4. Multi-region writes — global write latency reduction. Higher complexity; only when single-master truly hurts.

Don’t pre-emptively add regions. Each one costs storage and complicates your conflict story (in multi-master). Start with two regions (one for DR), upgrade to multi-master only when the latency math justifies it.

🎯 Common questions
Q1. How does the SDK pick which region to read from?

You configure `PreferredLocations` — an ordered list, e.g. `["West US 2", "East US"]`. The SDK tries the first available; falls through if it's down. With no preferences, it picks the account's default read region.

Q2. What does "automatic failover" do, exactly?

If your write region becomes unavailable, Cosmos promotes the next region in your priority list to write region within seconds. Your app may see a few seconds of write failures, then resumes. When the original region recovers, Cosmos can fail back automatically (configurable).

Q3. Can two regions accept writes to the same document at the same instant?

Yes — that's the conflict case. With LWW, the later timestamp wins (clocks are synchronized via NTP, with the same backoff trick Spanner uses). With custom merge, your stored procedure runs server-side once both writes are visible and decides the winner.

📺 Video

The lesson video is on YouTube — coming once the upload goes public.

🧪 Simulator

A live simulator for this lesson's mechanic (e.g. RU calculator, partition-key picker). Coming in Phase 2.

🎨 Visualization

An interactive diagram of this lesson's core idea — coming as we build out the visualization library.

💻 Code

A copy-paste reference snippet plus a short build challenge.

Comments 0

Discuss this page. Markdown supported. Be kind.

Loading…
Loading comments…