A customer changes their delivery address through an application in one region. At almost the same moment, a support agent updates the delivery instructions through another region. Both requests succeed, but after replication catches up, one change has disappeared.
Nothing necessarily failed at the network or storage level. Each region accepted a change based on information that did not include the other change. The application now needs a rule for combining or choosing between those decisions, and that rule must make sense for the data involved.
Introduction
Writing in several regions can keep requests close to users and allow selected work to continue when regions cannot communicate. Those benefits introduce a question that a single authoritative writer often hides: what should happen when separate writers modify the same thing independently?
We will use a delivery profile replicated between Region North and Region South. We will follow a concrete lost update, compare several resolution strategies and examine cases where preserving both changes is still insufficient to protect the application's rules.
The article focuses on systems that can accept local writes before a shared global order is established. Not every multi-region database works this way. Some coordinate writes across locations, so the selected database mode and transaction guarantees are essential parts of the design.
The aim is to make the product decision visible. Should one value win, should compatible changes merge, should conflicting versions be shown to a person, or should these writes go through one coordinated authority? A database can implement a chosen rule, but it cannot infer which customer intention matters most.
Follow two edits from the same starting record
Both regions begin with this delivery profile:
{
"profileId": "profile-42",
"street": "12 Harbour Road",
"postcode": "HB1 2AB",
"instructions": "Leave with a neighbour"
}
The customer reads that profile in North and changes the address to 8 Garden Lane with postcode GL4 5CD. Their application sends a complete replacement document containing the new address and the unchanged delivery instructions.
Meanwhile, a support agent reads the old profile in South and changes the instructions to "Call on arrival". That interface also sends a complete replacement document. It contains the new instructions but still includes the old Harbour Road address.
Suppose communication between regions is delayed. North accepts the customer's replacement, and South accepts the support agent's replacement. Each request is valid against the local copy it read. Neither region has seen the other accepted write yet.
When the replacements meet, choosing North's complete document loses the instruction change. Choosing South's complete document restores the old address. Both interfaces may have displayed success even though no eventual winner contains both intended edits.
Concurrent means neither change knew about the other
In everyday language, concurrent often means occurring at exactly the same moment. In this problem, the more useful meaning is that neither operation was based on the result of the other. The requests could be seconds apart and still be concurrent in that sense.
If South receives North's change before the agent reads the profile, the agent can edit the new address document. That is a later edit in a shared history. If South has not received it, the agent works from an older branch even when their wall-clock time is later.
This distinction is called causality: whether one operation has information about another operation's outcome. It matters because a later timestamp does not prove that a person knowingly replaced a newer value.
Replication delay creates more opportunity for concurrent edits, but the correctness rule must also work during an extended communication failure. "Our replication is normally fast" describes frequency, not what happens when the conflict occurs.
For the delivery profile, record which version an edit was based on. That context helps distinguish an intentional later change from an independent edit of an old copy. Without it, the receiving system sees only two replacement documents and has less evidence about how they were created.
Last write wins gives a winner, not an explanation
A common rule is last write wins, often shortened to LWW. The system assigns an ordering value to writes and retains the candidate that wins under that ordering. It also needs a deterministic tie-break rule so every replica makes the same choice.
This can be a reasonable contract for data where one latest chosen value is sufficient, such as a non-critical display preference. It is less suitable when losing an independently accepted change would surprise the user or break a business process.
The word "last" needs a precise definition. It might refer to a database-managed timestamp or a configured ordering property. It should not casually mean whichever message a replica happened to receive most recently, because delivery order can differ between replicas.
Azure Cosmos DB's conflict resolution policies describe its LWW and custom options for multiple write regions, including API-specific behaviour. Those are concrete service contracts to inspect; a generic LWW label does not tell you the whole policy.
In our example, LWW can make all replicas agree on one document while still losing either the new address or the new instructions. Agreement is valuable, but agreement and preserving every meaningful user action are different properties.
Clocks cannot discover customer intent
Suppose South's timestamp sorts after North's. The support agent's document wins, including its stale copy of the address. The system has followed its rule consistently, but the agent never intended to move the customer back to Harbour Road.
Using timestamps from phones or browsers introduces additional uncertainty because their clocks may be incorrect. Even well-maintained server clocks do not make timestamp order equivalent to the order in which users learned about one another's changes.
Do not fix this by asking every client to send a larger timestamp. A client that accidentally sends a far-future value can dominate later updates under a poorly designed policy. Ordering metadata needs a trusted owner and a defined range and comparison rule.
Logical ordering mechanisms can represent relationships without relying solely on wall-clock time, but they still do not decide the business meaning of a conflict. Knowing that two edits are independent tells you that a choice is needed; it does not tell you which address a parcel should use.
Keep timestamps useful for observation while avoiding claims they cannot support. A support view can show when edits were received and what each changed, alongside version context. Presenting one timestamp as unquestionable proof of user intent can make manual resolution less accurate.
Send the change the user actually made
The first improvement to the delivery profile is to avoid sending unchanged fields as though the user edited them. The customer intended to replace the address; the support agent intended to replace the delivery instructions. Those are narrower operations than replacing the entire profile.
An application-level command could say:
ChangeAddress(profile-42, expectedAddressVersion, newAddress)
ChangeDeliveryInstructions(profile-42, expectedInstructionsVersion, text)
This representation gives the receiving system more information about intent. It can preserve unrelated changes when the data model and storage protocol support that behaviour. It also lets the application validate the particular operation instead of accepting every field in a replacement payload.
However, using an HTTP PATCH request does not automatically create safe global field merging. The database may still resolve conflicts at whole-item granularity, and two patches can target the same field. Read the selected API and database contract before relying on the narrower request shape.
Separating truly independent data into independently versioned records can reduce accidental conflicts. The trade-off is that reads and transactions spanning those records may become more complex. Choose boundaries based on which values need to change together, rather than splitting every property mechanically.
Merge fields only when their meaning allows it
The street and postcode form one address. Merging North's street with South's postcode can produce a combination that nobody entered and that may identify no valid destination. A field-level merge can retain more individual values while creating a worse overall record.
Treat related fields as a consistency unit: a group whose values must make sense together. For this profile, the address can be replaced as one unit, while delivery instructions may be independent enough to update separately.
Now consider two users both changing the complete address. North chooses Garden Lane, and South chooses Station Avenue. There is no ordinary string merge that discovers the correct destination. Concatenating the streets, choosing the longest text or combining postcodes would invent a third answer.
The application needs a documented rule. It might require confirmation from the customer, prefer an authorised verified-address workflow or route address changes through one authority. Each choice has consequences for availability, user experience and operational work.
Write examples of invalid merged states before implementing a resolver. Include related dates, currency and amount, ownership and permissions, or status and status reason where relevant. A resolver that operates on arbitrary JSON properties cannot assume that every property is semantically independent.
A local version check is not necessarily a global lock
Many applications use optimistic concurrency: the client sends the version it read, and the database accepts the change only if that version is still current. Against one coordinated authority, this can detect that another writer changed the record first.
Suppose North and South each hold version 17 and can independently accept writes during a partition. Each checks its own copy, sees version 17 and accepts an update to a local version 18. Both checks succeeded, yet the global conflict remains.
The problem is the scope of the check. A condition evaluated against local state does not automatically coordinate with every regional writer. An ETag or version field is useful only within the concurrency guarantees provided by the service handling it.
Database modes can differ significantly. The DynamoDB global tables core concepts distinguish multi-region eventual and strong consistency, including different transaction capabilities. In its eventual-consistency mode, a transaction's local atomicity does not mean its writes appear as one atomic unit in every remote replica.
State the required guarantee before selecting the mechanism. If the rule is "only one request anywhere may reserve this item", verify that the actual read-and-write operation enforces that global rule. A successful local condition is not sufficient evidence by itself.
Preserve conflicting versions when automatic choice is wrong
Some systems retain multiple concurrent versions instead of immediately discarding all but one. The application can inspect those versions and resolve them according to domain rules. This preserves evidence that would disappear under a winner-only policy.
Riak's conflict resolution documentation describes concurrent values, often called siblings, and the context used to recognise their relationships. The terminology is product-specific, but the idea is accessible: keep the competing answers until there is a justified way to settle them.
For the delivery profile, a conflict record could preserve both proposed addresses, the version each edit used and the actor authorised to make it. The normal application should then avoid silently treating either proposal as a confirmed shipping destination.
A resolution is itself a write. It must be based on the versions it resolves and must detect a new edit arriving while somebody reviews the conflict. Otherwise, an operator can resolve yesterday's conflict by accidentally overwriting today's valid customer update.
Preserving versions also creates operational responsibilities. Bound the amount of retained conflict data, protect access to personal information and track unresolved age. A system that keeps every conflict but never surfaces or resolves it has deferred the problem rather than completed the design.
Walk through a customer resolving two addresses
Suppose the system preserves the two conflicting address proposals instead of choosing automatically. It gives the conflict an identifier and records the exact candidate versions: North proposes Garden Lane, while South proposes Station Avenue. The account page explains that two address changes need confirmation and shows both complete addresses.
The customer selects Garden Lane. The client sends a resolution command naming the conflict and the candidate versions it displayed. A coordinated resolution authority checks that those candidates still describe the unresolved state before recording the decision. This prevents the interface from turning a stale page into an unconditional overwrite.
Now imagine a third edit arrives while the customer is reading the page. A support agent corrects Garden Lane's postcode after speaking to the customer. The original resolution command no longer covers the current set of changes. The authority should reject that stale resolution or apply a documented rule that preserves the newer information, then let the client refresh its view.
If the resolution response is lost, retrying with the same resolution-operation identifier should discover the decision already recorded. Otherwise, a retry can look like a fresh instruction and interfere with subsequent edits. The operation's identity and the candidate context answer different questions: whether this request was already handled, and whether its view of the conflict is still valid.
Once resolved, the application propagates the resulting state using its supported replication protocol. A delayed copy of the original South proposal must not create the same unresolved conflict again. The resolution therefore needs causal or version context that identifies the history it has settled, not just a new address string with today's timestamp.
The example also needs a practical fallback. If the customer never visits the page, future orders may have to require an explicit address selection instead of silently using either proposal. Existing dispatched orders should retain the destination fixed by their own workflow.
This approach is more work than choosing a winner, which is precisely the trade-off to evaluate. Preserving intent is worthwhile only when the application supplies a complete path from conflicting proposals to a usable decision. A conflict table with no owner, client behaviour or completion rule leaves the difficult part unfinished.
Some operations can be designed to merge safely
Certain data types have operations that can be combined under carefully defined rules. These are often called conflict-free replicated data types, or CRDTs. Their guarantees come from the data representation and merge rules, not from a database simply retrying updates until they stop failing.
An introductory example is a grow-only counter. Instead of both regions replacing one total, each maintains its own non-decreasing component. The visible total is the sum of those components.
Initial components: North 3, South 2, total 5
North adds one: North 4, South 2, local total 6
South adds one: North 3, South 3, local total 6
After merge: North 4, South 3, total 7
The merge takes the greatest known value for each component. Receiving the same state twice does not add it twice, and receiving an older state cannot reduce a component. This assumes stable component identities and correctly serialised increments within each component's owner; two uncoordinated writers must not both claim to be the same owner.
The original CRDT research paper develops these convergence conditions. The example is a teaching model for the representation, not a complete production counter: persistence, ownership changes, overflow and lifecycle still require a supported implementation.
Convergence does not protect every business constraint
A counter that eventually includes every increment can be useful for a count of views. It does not automatically prevent two regions from selling the final seat. Preserving both sales accurately would reveal an oversell rather than prevent it.
Suppose North and South each believe one seat remains. Each accepts a purchase while communication is unavailable. Merging the purchase records produces two validly recorded decisions for one resource. No rule for adding numbers can make both promises simultaneously true.
One solution is coordinated reservation through an authority that can enforce the limit. Another is to allocate separate rights in advance. If five seats are divided into three rights for North and two for South, each region can consume only its own allocation while disconnected.
That allocation approach changes availability. North may reject a purchase after consuming its three rights even while South has two unused rights. Transferring rights safely requires coordination, and a failed region's allocation cannot simply be reused elsewhere while the old owner can still spend it.
The lesson is to distinguish mergeable facts from constrained decisions. "These two clicks happened" and "only one customer may own this seat" need different guarantees. Choose a resolution strategy for each operation according to the promise it makes.
Route sensitive writes through a coordinated authority
An application can serve reads from several regions while routing writes for a particular customer or entity to one authority. This reduces the number of independent decisions that need to be reconciled later.
For the delivery profile, a home region could own address changes. Other regions forward those commands there or return a temporary inability to change the address when the authority cannot be reached. Delivery instructions might use a different policy if their business impact permits it.
This is a trade-off, not a failure to build a distributed system. The application still has regional availability and latency considerations, but its critical writes have a clearer ordering point. Ownership transfers must be controlled so two regions do not both consider themselves the current authority.
A database can also provide a coordinated multi-region transaction model. Google's Spanner consistency documentation describes its default external-consistency guarantee. Such coordination changes the problem: writers rely on the database's ordering and transaction contract instead of accepting independent conflicting commits for later application merging.
Stronger coordination has latency, topology and availability consequences. Evaluate those against the cost of manual conflict resolution or broken business rules. A slightly slower confirmed decision can be more useful than a fast local success that the application later retracts.
Make a success response match the actual promise
If a regional write can later lose to another concurrent write, what does its successful response mean? It may mean the region accepted the proposal, not that the value is globally final and will remain the selected outcome.
For a collaborative preference editor, that distinction may be acceptable if subsequent updates and conflict notifications are visible. For a delivery address used immediately to dispatch a parcel, the same ambiguity can be unacceptable.
Define states around the business process. An address change could be proposed, confirmed for future orders or rejected because an order has already entered dispatch. The authority that freezes an order's delivery details should follow the guarantees required for that irreversible step.
Avoid copying a mutable profile into a shipping label before its relevant decision is settled. Once the parcel leaves the warehouse, making database replicas agree on a different address cannot undo the physical action.
Likewise, email notifications should describe the actual stage reached. Sending "your address is confirmed" after only a provisional regional acceptance creates a customer promise that the storage policy may not preserve. Align the user interface, notification wording and workflow with the same definition of completion.
Treat deletion and recreation as explicit operations
A delete can conflict with an update just as two edits can conflict with one another. North might remove a saved address while South modifies an older copy. The system needs a rule for whether the update can restore it.
Do not assume every database uses the same deletion policy. A service may give deletion priority, compare timestamps or expose the conflict for custom handling. Check the documented behaviour of the exact API and mode rather than transferring expectations from another product.
If recreation is supported, give it an explicit identity and contract. Reusing the same record identifier without distinguishing lifetimes can allow delayed edits from the old record to affect a newly created one. A generation or new immutable identifier can separate those lifetimes.
Keep enough deletion and ordering information to reject stale updates for the supported replay and offline window. Once that history is discarded, an old client may need a fresh baseline instead of ordinary incremental synchronisation.
These rules belong alongside ordinary edit rules in the design. Treating deletion as an unrelated maintenance operation leaves a gap exactly where old regional state is most likely to produce a surprising result.
Test the resolver with reordered and repeated information
Start with the delivery profile example and pause communication between two controlled regional instances. Apply the address change in one and the instruction change in the other. Resume communication and check both the final values and what each client was told.
Then make both regions change the address to different destinations. A test that passes for independent properties does not establish that conflicting properties are safe. Verify the documented winner, conflict record or coordinated rejection rather than merely checking that the replicas eventually match.
For a state-merge function, test receiving inputs in different orders, grouping them differently and receiving the same state repeatedly. A merge designed to converge despite these conditions should give the same result. Operation-based designs have their own delivery assumptions, so test the guarantees actually required by the chosen implementation.
Include process restarts and a delayed old update after resolution. The context that protects the decision must survive recovery. Also test a new edit arriving while a person is resolving an earlier conflict.
Check business constraints separately from convergence. Every replica agreeing on two reservations for one seat is a failed business test. Record the intended invariant in plain language and assert it alongside the technical equality checks.
Make conflicts observable and reviewable
Track conflict frequency, unresolved age and the operations most often involved. A rise after a deployment can reveal that a client started replacing full documents instead of sending focused changes. A rise during regional disruption can confirm that the application is exercising its independent-write policy.
Preserve useful context without exposing unnecessary personal information in logs. Entity identifiers, base versions, operation types and resolution decisions often provide a clearer investigation path than copying complete addresses into general telemetry.
If manual resolution is part of the contract, provide a controlled interface that shows what each actor changed and checks that the underlying versions are still current. Operators should not need to reconstruct intent from two unexplained JSON blobs and then issue an unconditional overwrite.
Review the cost of the policy over time. Frequent conflicts or growing manual work may justify changing ownership boundaries, splitting independent records or coordinating selected writes. Multi-region design is not one global setting that every field must share forever.
Summary
Two regions can accept conflicting updates when neither write includes the other's result. A deterministic winner can make replicas agree, but it may discard a meaningful change. Field merging helps only when the fields are truly independent, and local version checks protect only the coordination scope they actually cover.
Choose a rule that fits the operation: preserve and resolve competing versions, use a suitable mergeable data type, allocate independent rights or route constrained decisions through a coordinated authority. Make the success response reflect what the system has established.
Test concrete conflicts, delayed delivery and recovery, then verify both replica agreement and business rules. The goal is not simply to end with one record everywhere. It is to end with a result that the application can explain and its users can rely on.
