ACID vs BASE
Strong consistency (ACID) or high availability (BASE) — the database design spectrum.
Intent & Description
🎯 Intent
Choose the right consistency model for your database based on whether data correctness or system availability is more important.
📋 Context
Traditional relational databases (PostgreSQL, MySQL) provide ACID transactions — every transaction is all-or-nothing, isolated from others, and permanently recorded. NoSQL databases (Cassandra, DynamoDB) embrace BASE — data is always writable, may be briefly inconsistent, but converges over time. The trade-off is strict correctness vs. horizontal scalability.
💡 Solution
Use ACID when data integrity is non-negotiable — banking, inventory, orders, user accounts. Use BASE when availability and scale are priorities — social feeds, analytics, caching, IoT sensor data. ACID databases scale vertically — bigger machines, limited horizontal scaling. BASE databases scale horizontally — add nodes linearly, accept eventual consistency. Many systems use both — ACID for core transactional data, BASE for derived analytics.
Real-world Use Case
📌 TL;DR
ACID = strict consistency, limited scale. BASE = eventual consistency, unlimited scale. Choose ACID for transactions where correctness matters. Choose BASE for analytics, caching, and global services where availability matters more than immediate consistency.
Advantages
- ACID provides strong guarantees — prevents data corruption, simplifies application logic
- BASE enables massive horizontal scaling — handle global traffic with linear node addition
- BASE systems remain available during network partitions — AP from CAP theorem
- Clear mental model for choosing database technologies based on use case
Disadvantages
- ACID limits scalability — vertical scaling has hard limits, horizontal scaling is complex
- BASE requires handling inconsistent data in application logic — more complex reasoning
- BASE has latency in convergence — data may be stale for seconds to minutes
- The spectrum is continuous, not binary — many databases offer tunable consistency levels
// ACID Transaction Example
async function transferMoney(fromAccount, toAccount, amount) {
const db = await getACIDDatabase();
await db.transaction(async (tx) => {
// Atomic: both succeed or both fail
const balance = await tx.query(
'SELECT balance FROM accounts WHERE id = $1',
[fromAccount]
);
if (balance.rows[0].balance < amount) {
throw new Error('Insufficient funds');
}
// Isolated: no other transaction sees intermediate state
await tx.query(
'UPDATE accounts SET balance = balance - $1 WHERE id = $2',
[amount, fromAccount]
);
await tx.query(
'UPDATE accounts SET balance = balance + $1 WHERE id = $2',
[amount, toAccount]
);
// Durable: changes are permanent once committed
});
}
// BASE Model Example
async function updateUserProfile(userId, profileData) {
const db = await getBASEDatabase();
// Write immediately to local node
await db.writeToLocal(userId, profileData);
// Async replication (fire and forget)
db.replicateToOtherNodes(userId, profileData)
.catch(err => console.log('Replication failed, will retry later'));
// Data is available immediately but may be stale on other nodes
return { status: 'written', consistency: 'eventual' };
}
// Tunable Consistency Example
async function readData(key, consistencyLevel) {
const db = await getDatabase();
switch (consistencyLevel) {
case 'strong':
// Wait for quorum acknowledgment
return await db.readFromQuorum(key);
case 'eventual':
// Read from any node, fastest
return await db.readFromAnyNode(key);
case 'bounded_staleness':
// Read from nodes within specific time window
return await db.readFromRecentNodes(key, '5s');
}
}