AlgoInsight

System Design

What Are ACID Transactions?

ACID is the set of guarantees that lets you trust a database with money. Four letters, four promises - and understanding exactly what each one means is foundational for system design. Here's each, with a concrete example of what breaks without it.

By Admin2026-06-1814 min readacidtransactionsdatabasesconsistencysystem-designsql

When you transfer money between two bank accounts, a lot has to go right. The money has to leave one account and arrive in the other - never one without the other. If the system crashes mid-transfer, you can't end up with money vanished or duplicated. If two transfers happen at once, they can't corrupt each other. And once the transfer is confirmed, it has to stay confirmed even if the power dies a second later. The set of guarantees that makes all of this trustworthy is called ACID - four properties that let you hand a database your most critical data and trust it completely.

ACID is foundational, and understanding precisely what each letter promises (and what breaks without it) is essential for reasoning about databases in system design. Let's take them one at a time, grounded in that money-transfer example.

First: what is a transaction?

ACID describes the properties of a transaction - a unit of work that groups one or more operations together so they behave as a single, indivisible action. The money transfer is a transaction: it bundles "subtract from account A" and "add to account B" into one unit that should happen completely or not at all. A transaction is how you tell the database "treat these operations as one - don't let them be half-done."

ACID is the set of guarantees the database makes about how transactions behave. The letters stand for Atomicity, Consistency, Isolation, and Durability.

stateDiagram-v2
    [*] --> Active: BEGIN transaction
    Active --> Committed: COMMIT (all operations succeed)
    Active --> Aborted: ROLLBACK / error
    Committed --> [*]: changes durable
    Aborted --> [*]: no changes (as if never happened)
This state diagram shows a transaction's lifecycle. A transaction begins and enters the active state, where its operations run. From there it either commits - if all operations succeed, making its changes durable - or aborts, through a rollback or an error, leaving no changes as if it never happened. This all-or-nothing outcome is the essence of atomicity.

A - Atomicity: all or nothing

Atomicity means a transaction is all-or-nothing: either all its operations succeed, or none of them do. There's no partial completion. If any part of the transaction fails, the entire transaction is rolled back, leaving the data as if the transaction never happened.

In the money transfer: atomicity guarantees you can't subtract from account A without adding to account B. If the system fails after the subtraction but before the addition, atomicity ensures the subtraction is undone - the money isn't lost. The transaction either completes entirely (money moves) or not at all (nothing changes). Without atomicity, a failure mid-transaction leaves money vanished or created from nothing - the most basic corruption there is.

This is why atomicity is the property people most associate with transactions: it's the "treat these operations as one indivisible unit" promise.

C - Consistency: valid state to valid state

Consistency means a transaction takes the database from one valid state to another valid state, never leaving it in a state that violates its rules. The database's rules - constraints, like "an account balance can't go negative," or "every order must reference a real customer" - are always respected. If a transaction would violate a rule, it's rejected rather than allowed to corrupt the data.

In the money transfer: consistency ensures that defined rules hold - if there's a rule that balances can't go negative, a transfer that would overdraw account A is rejected, keeping the data valid. The total money in the system is preserved (what leaves A equals what arrives at B). Consistency is what guarantees the database never ends up in a state its own rules say is impossible.

(A note on the word: "consistency" here - valid state per the database's rules - is different from "consistency" in the CAP theorem sense of all nodes agreeing. Same word, different concept. This trips people up constantly.)

I - Isolation: concurrent transactions don't interfere

Isolation means concurrent transactions don't interfere with each other - each transaction behaves as if it were running alone, even when many run at the same time. The intermediate, half-finished state of one transaction isn't visible to others; they see the data as it was before, or as it is after, but not a corrupted in-between.

In the money transfer: imagine two transfers touching the same account simultaneously. Without isolation, they could read and write the balance in an interleaved way that corrupts it - both read the same starting balance, both update from it, and one update is lost. Isolation prevents this, ensuring the transfers don't step on each other and the balance ends up correct as if they'd run one after another.

Isolation has levels - databases offer a spectrum from strict (transactions fully isolated, as if perfectly sequential) to relaxed (some interference allowed for better performance). Stricter isolation is safer but can be slower; weaker isolation is faster but allows certain anomalies. Choosing the isolation level is a real trade-off between correctness guarantees and performance, and it's one of the more subtle parts of working with transactions.

D - Durability: it survives crashes

Durability means once a transaction is committed, it stays committed - permanently - even if the system crashes immediately after. The confirmed change is safely persisted and will survive power loss, restarts, and failures.

In the money transfer: durability guarantees that once you're told the transfer succeeded, it did - even if the database crashes a half-second later, the completed transfer is still there when it recovers. Without durability, a crash could undo a transaction you were already told had succeeded, which would make any confirmation meaningless.

Durability is delivered through mechanisms like write-ahead logging - the database records committed changes to a durable log so they survive crashes. (See the dedicated guide on how databases guarantee durability after a crash for exactly how this works.)

Isolation levels and the anomalies they prevent

Isolation deserves a deeper look, because it's the most nuanced of the four and the source of subtle bugs. The reason isolation has levels is that perfect isolation (every transaction behaving exactly as if it ran completely alone, one after another) is expensive, so databases offer weaker levels that allow more concurrency at the cost of permitting certain anomalies. The classic anomalies, in increasing order of how much isolation you need to prevent them:

Stronger isolation levels prevent more of these anomalies, up to the strictest level (often called serializable), where transactions behave as if they ran strictly one at a time, preventing all of them. The trade is performance: stronger isolation means more coordination and less concurrency. Choosing the right isolation level means deciding which anomalies your application can tolerate versus how much concurrency you need - a genuine engineering decision, not a default to ignore.

Atomicity in action: the rollback

Make atomicity concrete with the mechanics of a rollback. A transaction begins. It subtracts

00 from account A - this change is made within the transaction. It attempts to add
00 to account B, but something fails (a constraint violation, a crash, an error). Because the transaction can't complete fully, the database rolls back: the subtraction from account A is undone, returning the data to exactly its state before the transaction began. The client gets an error, and crucially, no money was lost - account A still has its
00.

Contrast the no-atomicity world: the subtraction happens, the addition fails, and there's no rollback -

00 simply vanishes. Atomicity is the machinery that makes "all or nothing" real: the database tracks a transaction's changes and can undo them entirely if it can't complete. This is why you wrap related operations in a transaction - so the database guarantees they either all happen or all unwind.

How transactions are used in practice

You use transactions explicitly with a simple structure: mark the beginning of a transaction, perform your operations, then either commit (make all changes permanent) or roll back (discard them all). In SQL that's roughly BEGIN, your statements, then COMMIT or ROLLBACK. If anything goes wrong, you roll back and the database unwinds everything; if all is well, you commit and ACID guarantees the changes are atomic, consistent, isolated, and durable. Most database libraries wrap this so an error automatically triggers a rollback, ensuring you never accidentally leave a transaction half-done. The four ACID properties are what the database promises about this begin-operations-commit structure - the guarantees that make wrapping operations in a transaction worth doing.

Consistency, more precisely

Consistency (the C) is the most debated of the four, because it overlaps with the application's own responsibility. The database guarantees a transaction won't violate the rules it knows about - constraints like uniqueness, foreign keys (every order references a real customer), check conditions (a balance can't go negative), and the like. If a transaction would break one, the database rejects the whole transaction (which, via atomicity, rolls it back), keeping the data valid.

But "consistency" in the fullest sense - that the data is meaningfully correct for your application - is partly the application's job: the database enforces the rules you've defined, and it's on you to define rules that capture what "valid" means for your domain. So consistency is a partnership: you declare the constraints that define a valid state, and the database guarantees transactions never leave the data violating them. The stronger your constraints, the more the database protects you - which is why well-designed schemas with proper constraints are so valuable, turning the database into an active guardian of validity rather than a passive store. And the four properties reinforce each other here: atomicity ensures a rule-violating transaction rolls back completely, and isolation ensures concurrent transactions don't conspire to reach an invalid state neither would reach alone. Consistency is, in a sense, the goal the other three properties serve.

Why ACID matters

Put the four together and you have a database you can trust with critical data: transactions are all-or-nothing (atomicity), never violate the rules (consistency), don't corrupt each other when concurrent (isolation), and survive crashes once committed (durability). This is precisely what you need for anything where correctness is non-negotiable - financial systems, inventory, orders, bookings, anywhere a half-completed or corrupted or lost transaction causes real harm.

ACID is the reason relational databases are the default for this kind of data. When the data must be correct, ACID transactions are how you guarantee it - and that guarantee is doing real, constant work every time money moves, an order is placed, or inventory is decremented, even though the application code that wraps a few operations in a transaction looks almost trivially simple.

ACID vs. BASE: the other end of the spectrum

It's worth knowing that ACID isn't the only model. Many NoSQL systems, built for massive scale and high availability, relax ACID's strict guarantees in favor of an approach often summarized as BASE (Basically Available, Soft state, Eventually consistent). These systems trade strong consistency and strict transactions for scalability and availability - accepting eventual consistency (data converges over time rather than being instantly consistent everywhere) to scale across many machines and stay available.

This connects to the CAP theorem: at scale, you trade between strong consistency and availability, and ACID and BASE sit at different points on that spectrum. The choice isn't "which is better" but "which fits the data" - ACID where correctness is critical (money), BASE-style eventual consistency where scale and availability matter more and brief staleness is acceptable (feeds, counts). (See the SQL vs NoSQL and consistency-models guides.)

Tip: Emeka's note from the data trenches: The practical wisdom about ACID is knowing which data actually needs it. It's tempting to either demand ACID everywhere (and pay for it in scale you might not afford) or wave it away for everything (and corrupt data that needed protection). The skill is matching the guarantee to the data: the transactional core - payments, orders, anything where a lost or half-done operation is a real problem - gets a database with full ACID transactions, no compromise. The high-volume, low-stakes data - activity events, view counts, feeds - can live in systems with relaxed guarantees that scale more freely. In real systems I've built, both coexist: ACID where correctness is sacred, eventual consistency where scale and availability win. Knowing where to draw that line is the actual expertise.

Interview: ACID is fundamental and comes up constantly. Be able to state each property crisply - atomicity (all or nothing), consistency (valid state to valid state), isolation (concurrent transactions don't interfere), durability (survives crashes) - ideally with a concrete example like the money transfer. The stronger signal is knowing when you need ACID (correctness-critical data) versus when relaxed guarantees suffice (high-scale, low-stakes data), and that this connects to the SQL-versus-NoSQL and CAP trade-offs. That shows you understand ACID not as trivia but as a design decision.

The bottom line

ACID is the set of four guarantees that make a database trustworthy for critical data. Atomicity - a transaction is all-or-nothing, never half-done. Consistency - transactions take the database from one valid state to another, never violating its rules. Isolation - concurrent transactions don't interfere, each behaving as if alone (with isolation levels trading strictness against performance). Durability - once committed, a transaction survives any crash. Together, on the money-transfer example, they ensure money moves completely or not at all, never breaks the rules, isn't corrupted by concurrent transfers, and stays done once confirmed.

ACID is why relational databases are the default for correctness-critical data, and BASE-style eventual consistency is the scalable alternative for data where availability and scale matter more. Knowing which data needs which is the real expertise. We cover transactions and the guarantees behind them across System Design Fundamentals.


Go deeper

More articles