Overview
Isolation is the “I” in acid. SQL defines four levels; PostgreSQL implements three distinct ones. Pick the level per transaction by which anomaly would corrupt your data, such as double-booking or lost updates. Stronger levels abort transactions with SQLSTATE 40001, so the application must retry the whole transaction.
Rules
- Isolation is built on mvcc snapshots in PostgreSQL. Read Committed (the default): each statement sees data committed before it began. Read Uncommitted behaves identically, so PostgreSQL never allows dirty reads.
- Repeatable Read: one snapshot for the whole transaction. PostgreSQL’s version also prevents phantom reads, but write skew is still possible.
- Serializable: behaves as if transactions ran one at a time, using serializable snapshot isolation. It aborts a transaction when it detects a dependency cycle.
- Use Read Committed for most OLTP. Use Repeatable Read or Serializable for read-then-write decisions such as booking and reconciliation, and avoid Serializable on hot write paths unless you need it.
- Higher levels add no row locks for reads; deadlocks still come from explicit locking and write order (deadlock).
BEGIN ISOLATION LEVEL SERIALIZABLE;
SELECT count(*) FROM slots WHERE date = '2026-06-01'; -- one slot left
INSERT INTO bookings (date, user_id) VALUES ('2026-06-01', 42);
COMMIT; -- fails with 40001 if a concurrent transaction took the last slot; retryRelated
- acid: the guarantees isolation belongs to.
- deadlock: separate from serialization failures.
- optimistic-locking: an application-level alternative.
- postgres: MVCC and locking.
- prisma-transactions: isolation levels in Prisma.