Decide on consistency
Your data is replicated: across machines, or across regions far apart. Replicas that coordinate on every write are correct but slow and less available; replicas that act alone are fast but can disagree. A business rule must still hold, say "never give out more than 5,000 bonuses" or "a username is unique". How much coordination does that rule actually need?
You will end with how much coordination your rule needs, the consistency model that delivers it, and the staleness you promise out loud.
The questions go from cheapest to most expensive answer: stop at the first one that fits.
Decide
Can the operation be rewritten so the order of updates does not matter?
SET balance = balance - 100 instead of read, compute, write; adding to a set or a counter instead of overwriting.
Why
A computation can run on independent replicas and still converge exactly when adding facts never retracts a conclusion (it is monotone). Unions, counters that only grow and inserts qualify; uniqueness checks, "the maximum" and counts that must be complete do not.
Does the rule fit on a single row?
A CHECK constraint, or a UNIQUE index on one node.
Why
The engine enforces it at every level and in every topology, for free.
If two replicas each accept writes that are fine on their own, is the merged result still fine?
It is not, for uniqueness ('anika' registered in both regions) and for upper limits that writes push upward (each region gives out 570 of 1,000 bonuses). It is, for per-row checks, insert-only foreign keys and lower limits.
Why
This property, invariant confluence, is an exact test: an execution that never coordinates yet always keeps the rule exists if and only if merges preserve it. Coordination is needed for rules that fail it, and for nothing else.
Can you split the limit between replicas, so each spends its own share locally?
5,000 bonuses across three regions: give each region a share, and rebalance when one runs low.
Why
Each replica acts alone until its share runs out, so coordination happens once per refill instead of once per operation.
Can information reach a user faster through another channel than through your replication?
A user sends money, sees 'sent', and phones a friend who opens the app in another region; or a message on a queue overtakes the replica.
Why
Only real time is shared by every outside channel, so only a model anchored to real time (strict serializability, called external consistency in Spanner) closes that gap. Almost nobody needs it for reasons inside the database; they need it because of a faster path around it.
Where you can land
Rewrite the operation so it commutes
Use it when updates can be relative or additive.
Replicas apply updates in any order and converge. Convergent data types (CRDTs) package this for counters, sets and registers.
What it costs: it exists only where the operation has that algebra. Removing items from such structures leaves tombstones, and collecting them needs coordination.
A single-row constraint
Use it when the rule is about one row.
What it costs: the rule must fit in one row.
No coordination needed
Use it when merging independently valid writes keeps the rule.
Correctness is safe; the model you choose is now about what users see.
Before you build it
Choose for user experience, and give each client a token
Session guarantees (read your own writes, never go back in time) are cheap: the client carries a token saying what it has seen, and replicas wait or redirect until they have caught up. Every component must carry the token, and eventually one will not, so test for it.
State the staleness bound out loud
Say how stale a read can be, in seconds, and alarm on it. An unbounded guarantee is not a guarantee.
Check for faster outside channels anyway
If information can travel around your replication (question 5), users will see the gap regardless of the rule.
Split the budget (escrow)
Use it when the rule is an upper limit that can be divided between replicas.
Each replica gets a share of the remaining limit and spends it locally, coordinating only to rebalance.
What it costs: coordination rate ≈ consumption rate ÷ share per replica, paid for in stranded slack: units held at a replica where nobody is buying. 10,000 units across 10 replicas, consumed at 100 a second, means about one rebalance every 100 seconds per replica: 0.1 coordinations a second instead of 100.
Coordinate on the rule
Use it when the rule fails the merge test and cannot be split, but nothing outside overtakes replication.
Route the writes the rule depends on through one coordinated path (a leader, a consensus group, or a serializable transaction), and keep the rest local.
Before you build it
Pick the isolation level separately
A read-modify-write in application code rules out read committed; a check over several rows followed by a write into them rules out snapshot isolation. Work through Choose an isolation level.
State the staleness bound out loud
For everything outside the coordinated path, say how stale reads can be.
External consistency
Use it when information can reach users faster than your replication.
Transactions are ordered by real time: if one commits before another begins, everyone sees them in that order.
What it costs: a latency floor set by the distance between replicas, plus a real-time anchor bought one of three ways: commit wait under a bounded clock (Spanner), a round trip to a timestamp service, or restarts when a read meets an uncertain value (CockroachDB). The clock uncertainty is the same; only the bill changes.