Senior 3 min · June 25, 2026

ACID vs BASE: The Production Trade-Offs That Kill Systems at 3 AM

ACID vs BASE explained with real production failures.

N
Naren Founder & Principal Engineer

20+ years shipping large-scale distributed systems. Notes here come from systems that actually shipped.

Follow
Production
production tested
June 25, 2026
last updated
1,663
articles · all by Naren
 ● Production Incident 🔎 Debug Guide ⚙ Triage Commands
Quick Answer

Use ACID when you need strong consistency and can't tolerate stale reads (e.g., financial transactions). Use BASE when you need high availability and partition tolerance, and can tolerate temporary inconsistency (e.g., social media feeds, caching layers).

✦ Definition~90s read
What is ACID vs BASE?

ACID (Atomicity, Consistency, Isolation, Durability) and BASE (Basically Available, Soft state, Eventual consistency) are two sets of database design principles. ACID guarantees strict consistency for transactions, while BASE prioritizes availability and partition tolerance in distributed systems, accepting temporary inconsistency.

Think of ACID like a bank vault: every deposit and withdrawal is recorded instantly and exactly once.
Plain-English First

Think of ACID like a bank vault: every deposit and withdrawal is recorded instantly and exactly once. If the power goes out mid-transaction, the vault locks and nothing is lost. BASE is like a whiteboard in a busy office: someone writes a number, someone else erases it, and eventually everyone agrees on the final count. It's fast and works even if people are in different rooms, but you might see the wrong number for a moment.

Everyone says ACID is for banks and BASE is for everything else. That's a lie that'll cost you a pager alert at 3 AM. I've seen a social media feed built on Cassandra lose a user's post for 47 seconds because the read repair didn't trigger in time. I've also seen a payment service on PostgreSQL deadlock because the isolation level was too strict for the concurrency pattern. The real question isn't which one is better—it's which one hurts less when it fails. By the end of this, you'll know exactly which consistency model your system needs, how to configure it without cargo-culting, and the exact failure modes that'll wake you up.

Why ACID Exists: The Problem of Partial Writes

Before ACID, databases could leave your data in a half-baked state. Imagine transferring $100 from account A to B: if the power fails after debiting A but before crediting B, the money vanishes. ACID's Atomicity ensures the entire operation succeeds or fails as one unit. Consistency guarantees that any transaction brings the database from one valid state to another—no orphaned rows, no violated constraints. Isolation prevents concurrent transactions from seeing each other's partial work. Durability means once a transaction commits, it survives a crash. Without these, you can't build reliable financial systems, inventory management, or any application where data integrity is non-negotiable.

TransactionExample.systemdesignSYSTEMDESIGN
1
2
3
4
5
6
7
8
// io.thecodeforge — System Design tutorial

BEGIN TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE account_id = 'A';
UPDATE accounts SET balance = balance + 100 WHERE account_id = 'B';
COMMIT;
-- If the server crashes between the two updates, the transaction is rolled back.
-- Atomicity ensures both happen or neither.
Output
Transaction committed successfully.
Production Trap:
Don't assume ACID means zero data loss. If you use READ UNCOMMITTED isolation, you can still read dirty data. Always verify your isolation level in production—PostgreSQL defaults to READ COMMITTED, MySQL to REPEATABLE READ.
ACID vs BASE Trade-Offs for Production Systems THECODEFORGE.IO ACID vs BASE Trade-Offs for Production Systems Decision flow from consistency to availability with failure modes ACID: Atomicity, Consistency, Isolation, Durability Guarantees no partial writes; strong consistency BASE: Basically Available, Soft state, Eventual consistency Trades consistency for high availability Isolation Level Trap Serializable can deadlock; Read Committed may anomaly Stale Reads & Tombstones BASE failure: read outdated data; delete markers linger Decision Frame: Latency vs Consistency Choose ACID for correctness; BASE for uptime Overkill Zone: Neither fits Use specialized stores (e.g., time-series, graph) ⚠ Isolation level mismatch causes silent data corruption Always test with production concurrency; use Serializable for critical transactions THECODEFORGE.IO
thecodeforge.io
ACID vs BASE Trade-Offs for Production Systems
Acid Vs Base
ACID Atomicity in ActionTHECODEFORGE.IOACID Atomicity in ActionHow a fund transfer avoids partial writesBegin TXDebit $100 from Account APower FailSystem crashes mid-operationRollbackDebit undone, no money lostRetryRe-apply full transfer atomically⚠ Without atomicity, partial writes silently destroy dataTHECODEFORGE.IO
thecodeforge.io
ACID Atomicity in Action
Acid Vs Base

BASE: Trading Consistency for Availability

BASE emerged from the CAP theorem: when a network partition occurs, you must choose between consistency and availability. ACID systems choose consistency—they'll refuse to serve reads if they can't guarantee freshness. BASE systems choose availability—they'll serve whatever data they have, even if it's stale. This is why DynamoDB, Cassandra, and Couchbase are popular for high-traffic web apps. The trade-off is eventual consistency: after a write, reads may return old data for a window of time. For a social media 'like' counter, that's fine. For a medical records system, it's a lawsuit waiting to happen.

CassandraWriteExample.systemdesignSYSTEMDESIGN
1
2
3
4
5
6
7
8
9
10
11
12
// io.thecodeforge — System Design tutorial

// Cassandra write with eventual consistency
// This write succeeds even if only one replica acknowledges it.
// Reads may not see this update until the gossip protocol propagates.

INSERT INTO user_likes (user_id, post_id, liked_at) 
VALUES ('user123', 'post456', toTimestamp(now())) 
USING CONSISTENCY ONE;

// To force strong consistency, use QUORUM:
// INSERT INTO ... USING CONSISTENCY QUORUM;
Output
Write successful (1 replica acknowledged).
Senior Shortcut:
When using BASE stores, always set your read consistency to the same level as write consistency for critical paths. For example, if you write with QUORUM, read with QUORUM. This gives you strong consistency without sacrificing all availability.

When ACID Breaks: The Isolation Level Trap

ACID's Isolation comes in levels: READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, SERIALIZABLE. Each level prevents certain anomalies but adds locking overhead. The classic rookie mistake is using SERIALIZABLE everywhere 'for safety'. I've seen this bring down a payments service when the thread pool was exhausted at 3am because every transaction waited for locks held by other transactions. The fix? Use READ COMMITTED for most operations, and only escalate to SERIALIZABLE for operations that truly need it—like checking account balances before a withdrawal. Even then, consider optimistic locking with version numbers instead.

OptimisticLocking.systemdesignSYSTEMDESIGN
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// io.thecodeforge — System Design tutorial

-- Optimistic locking using a version column
-- No locks held, but transaction may fail on commit

BEGIN;
SELECT balance, version FROM accounts WHERE account_id = 'A';
-- Application checks version and computes new balance
UPDATE accounts 
SET balance = balance - 100, version = version + 1 
WHERE account_id = 'A' AND version = 5;
-- If version changed (another transaction updated), rows affected = 0
-- Retry the entire transaction
COMMIT;
Output
UPDATE 1 (if version matched) or UPDATE 0 (if version mismatch, retry needed).
Never Do This:
Don't use SERIALIZABLE isolation in a high-concurrency OLTP system without testing. The error you'll see: 'ERROR: could not serialize access due to read/write dependencies among transactions'. This causes massive retry storms and throughput collapse.

BASE Failure Modes: Stale Reads and Tombstones

BASE systems introduce two painful failure modes. First, stale reads: a client writes data, then immediately reads from a different replica that hasn't received the update yet. This breaks features like 'my profile shows my new name'. Mitigation: use read-after-write consistency by reading from the same replica that handled the write, or use quorum reads. Second, tombstones: in DynamoDB and Cassandra, deletes are just markers. If you delete a key and then immediately read, you might still get the old data because the tombstone hasn't propagated. This is a common source of bugs in session management. Always wait for a full gossip cycle (usually a few seconds) after a delete before relying on its absence.

DynamoDBReadAfterWrite.systemdesignSYSTEMDESIGN
1
2
3
4
5
6
7
8
9
10
11
12
// io.thecodeforge — System Design tutorial

// DynamoDB: ensure read-after-write consistency
// Write with default eventual consistency
await dynamo.putItem({ TableName: 'Sessions', Item: session }).promise();

// Read with strong consistency to see the write immediately
const result = await dynamo.getItem({ 
  TableName: 'Sessions', 
  Key: { sessionId: 'abc' },
  ConsistentRead: true  // This costs more RCUs but guarantees freshness
}).promise();
Output
Session object returned with latest data.
Interview Gold:
Interviewers love asking: 'How do you handle read-after-write consistency in DynamoDB?' The answer: use ConsistentRead=true on the GetItem call, but be aware it consumes twice the read capacity units and has higher latency.

Choosing Between ACID and BASE: The Decision Framework

Here's the blunt rule: if you can't afford to lose a single write, use ACID. If you can tolerate temporary inconsistency for higher throughput and availability, use BASE. But it's not binary. Many systems use both: an ACID relational database for the core transactional data (orders, payments) and a BASE cache or search index for read-heavy workloads (product catalog, user feeds). The key is to define your consistency boundaries. For example, an e-commerce site might use PostgreSQL for the order table (ACID) and Elasticsearch for product search (BASE). If the search index is stale by 5 seconds, customers might not see the latest review, but they can still buy. That's acceptable.

HybridArchitecture.systemdesignSYSTEMDESIGN
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// io.thecodeforge — System Design tutorial

// Hybrid pattern: ACID for writes, BASE for reads
// 1. Write to PostgreSQL (ACID)
BEGIN;
INSERT INTO orders (user_id, total) VALUES (123, 49.99);
COMMIT;

// 2. Asynchronously update Elasticsearch (BASE)
// This can fail without affecting the order
await elasticsearch.index({
  index: 'orders',
  body: { user_id: 123, total: 49.99 }
}).catch(err => console.error('Search index update failed', err));

// 3. Read from Elasticsearch for fast search
// May be slightly stale, but that's acceptable
Output
Order committed in PostgreSQL. Search index update may be asynchronous.
Production Trap:
Don't assume eventual consistency means 'eventually within milliseconds'. In a partitioned network, it can take minutes. Always set a TTL or timeout on your reads to avoid serving data that's too stale.
ACID vs BASE Decision FrameworkTHECODEFORGE.IOACID vs BASE Decision FrameworkWhen to choose each for production systemsACID SystemsCannot lose a single writeStrong consistency requiredLower throughput acceptableFinancial or inventory dataBASE SystemsTolerates temporary inconsistencyHigh throughput neededAvailability over freshnessLogs, feeds, or analyticsMany systems use both: ACID for core, BASE for scaleTHECODEFORGE.IO
thecodeforge.io
ACID vs BASE Decision Framework
Acid Vs Base

When Not to Use ACID or BASE: The Overkill Zone

ACID is overkill when you're building a logging system or an append-only event stream. You don't need transactions to insert a log line—a simple BASE store with high write throughput is better. BASE is overkill when you have a single-node application with low concurrency. Using Cassandra for a blog with 100 visitors/day is absurd—SQLite with WAL mode gives you ACID with zero operational complexity. Also, don't use BASE for anything involving money, inventory, or user identity. I've seen startups try to use MongoDB (BASE-ish) for a payment ledger. The result: duplicate charges and angry customers. Use the right tool for the job.

OverkillExample.systemdesignSYSTEMDESIGN
1
2
3
4
5
6
7
8
9
10
11
// io.thecodeforge — System Design tutorial

// Don't do this: using ACID for a simple log
// Overkill and slow
BEGIN;
INSERT INTO logs (message, timestamp) VALUES ('User logged in', NOW());
COMMIT;

// Better: just insert without transaction
INSERT INTO logs (message, timestamp) VALUES ('User logged in', NOW());
// Or use a BASE store like Kafka or S3
Output
Log inserted.
The Classic Bug:
Using ACID for a high-volume audit log will kill your write throughput. Each transaction adds overhead. Instead, batch writes or use an append-only log like Kafka.
● Production incidentPOST-MORTEMseverity: high

The 4GB Container That Kept Dying

Symptom
A microservice handling order placement would crash with OOMKilled every 15 minutes under moderate load. No obvious memory leak in heap dumps.
Assumption
Team assumed a memory leak in the JVM or a misconfigured connection pool.
Root cause
The service used PostgreSQL with SERIALIZABLE isolation. Under concurrency, transactions retried exponentially, each retry holding a snapshot of the entire database in memory. The 4GB container limit was hit because each retry accumulated more MVCC snapshots.
Fix
Changed isolation to READ COMMITTED and added retry logic with jitter. Also increased container memory to 8GB as a buffer.
Key lesson
  • SERIALIZABLE isolation is not free—it trades memory for correctness.
  • Always benchmark your transaction retry memory footprint under peak concurrency.
Production debug guideSystematic recovery paths for the failure modes engineers actually hit.3 entries
Symptom · 01
Deadlock detected in PostgreSQL
Fix
1. Run SELECT * FROM pg_locks WHERE NOT granted; to see blocked transactions. 2. Identify the conflicting queries. 3. Ensure all transactions access tables in the same order. 4. Consider lowering isolation level to READ COMMITTED.
Symptom · 02
Stale reads in Cassandra after a write
Fix
1. Check consistency levels: nodetool getconsistency. 2. Increase read consistency to QUORUM. 3. Verify replication factor and repair status: nodetool repair.
Symptom · 03
Duplicate writes in a BASE store
Fix
1. Check if idempotency keys are used. 2. Implement idempotency with a unique constraint or a TTL-based dedup table. 3. For DynamoDB, use conditional writes with attribute_not_exists.
★ ACID vs BASE Triage Cheat SheetFirst-response commands for when things go wrong — copy-paste ready.
Deadlock detected in PostgreSQL: `ERROR: deadlock detected`
Immediate action
Check pg_locks to see blocked processes
Commands
SELECT * FROM pg_locks WHERE NOT granted;
SELECT pg_cancel_backend(pid) FROM pg_locks WHERE NOT granted;
Fix now
Ensure consistent lock ordering in application code.
Stale read in Cassandra: read returns old data after write+
Immediate action
Check consistency levels
Commands
nodetool getconsistency
nodetool repair
Fix now
Set read consistency to QUORUM or LOCAL_QUORUM.
Duplicate writes in DynamoDB: same item inserted twice+
Immediate action
Check if idempotency key is used
Commands
Scan for duplicate keys in application logs
Check conditional write logic
Fix now
Use ConditionExpression: 'attribute_not_exists(PK)' on writes.
Transaction retry storm in PostgreSQL: high CPU and OOM+
Immediate action
Check number of active transactions
Commands
SELECT count(*) FROM pg_stat_activity WHERE state = 'active';
SHOW max_connections;
Fix now
Reduce isolation level, add retry jitter, or increase container memory.
Feature / AspectACIDBASE
Consistency modelStrong consistency (immediate)Eventual consistency (temporary inconsistency)
Availability during partitionMay become unavailableRemains available
PerformanceLower write throughput due to lockingHigher write throughput, eventually consistent reads
Use casesFinancial transactions, inventory, user accountsSocial media feeds, caching, session stores
Database examplesPostgreSQL, MySQL, OracleCassandra, DynamoDB, Couchbase

Key takeaways

1
ACID is not always safer—SERIALIZABLE isolation can cause retry storms that crash your service. Use the weakest isolation level that guarantees correctness.
2
BASE does not mean 'no consistency'—it means eventual consistency. You must design your application to handle stale reads, or use quorum for critical paths.
3
The best systems use both
ACID for the source of truth, BASE for read-optimized caches and indexes. Define clear consistency boundaries.
4
The counterintuitive truth
ACID databases can lose data too if you use READ UNCOMMITTED or don't fsync on commit. Always verify your durability settings.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01SENIOR
How does PostgreSQL handle concurrent transactions under SERIALIZABLE is...
Q02SENIOR
When would you choose DynamoDB over PostgreSQL for a user profile servic...
Q03SENIOR
What happens when you read from a Cassandra node that hasn't received a ...
Q04JUNIOR
What is the difference between READ COMMITTED and REPEATABLE READ isolat...
Q05SENIOR
You're debugging a production issue where a user's post appears after 10...
Q06SENIOR
How would you design a system that needs both ACID guarantees for paymen...
Q01 of 06SENIOR

How does PostgreSQL handle concurrent transactions under SERIALIZABLE isolation, and what happens when a conflict is detected?

ANSWER
PostgreSQL uses Serializable Snapshot Isolation (SSI). It tracks read-write conflicts using predicate locks. When a conflict is detected, one transaction is aborted with 'could not serialize access'. The application must retry. This is expensive—predicate locks consume memory and can cause performance degradation under high concurrency.
FAQ · 4 QUESTIONS

Frequently Asked Questions

01
What is the main difference between ACID and BASE in databases?
02
When should I use ACID instead of BASE?
03
How do I ensure read-after-write consistency in a BASE system like DynamoDB?
04
Can a database be both ACID and BASE?
N
Naren Founder & Principal Engineer

20+ years shipping large-scale distributed systems. Notes here come from systems that actually shipped.

Follow
Verified
production tested
June 25, 2026
last updated
1,663
articles · all by Naren
🔥

That's Database Internals. Mark it forged?

3 min read · try the examples if you haven't

Previous
Normalization vs Denormalization
5 / 9 · Database Internals
Next
Change Data Capture (CDC)