PostgreSQL Fundamentals

Snapshot Isolation

Learn what snapshot isolation means for PostgreSQL teams and how Vela uses consistent snapshots to give every branch a production-real starting point.

Definition

Snapshot isolation is a concurrency control mechanism where each transaction reads from a consistent point-in-time snapshot of the database, preventing dirty reads and non-repeatable reads without blocking writers.

Key takeaway: Snapshot isolation is what makes Vela branches production-real — each branch starts from a consistent snapshot that reflects the source database at a known moment, not a dump or a copy.

Snapshot isolation is a guarantee about what a transaction can see. When a transaction begins under snapshot isolation, PostgreSQL records the current transaction ID (XID) as the snapshot boundary. Any row version committed after that XID is invisible to the transaction, regardless of when the transaction reads the row.

Key Facts Snapshot Isolation
Type Concurrency control
Layer Transaction, not statement
Mechanism Point-in-time XID capture
Risk solved Non-repeatable reads

The practical effect is that readers and writers do not block each other. A long-running report query does not hold locks that prevent concurrent INSERTs or UPDATEs. Each transaction sees a stable, consistent view of the database for its entire duration.

Snapshot Isolation explainer: Active Transactions and Concurrent Writes enter the Snapshot at T0 engine, producing a Consistent Read View with no dirty reads

What Snapshot Isolation Means

Snapshot isolation is implemented on top of MVCC (Multi-Version Concurrency Control). PostgreSQL stores multiple versions of each row, each tagged with the XID of the transaction that created it. When a transaction reads under snapshot isolation, it only sees row versions whose creating XID is less than or equal to its own snapshot XID and that are committed.

This means:

  • Dirty reads are impossible. Uncommitted row versions from other transactions are never visible.
  • Non-repeatable reads are prevented. The same query returns the same rows each time within the transaction, because the snapshot does not advance.
  • Write-write conflicts are detected. If two transactions try to update the same row, one will be aborted with a serialization error.

Writers use the same MVCC machinery. An UPDATE creates a new row version rather than overwriting the existing one, leaving the old version visible to snapshot readers until VACUUM reclaims it.

Where Snapshot Isolation Appears in PostgreSQL

PostgreSQL exposes snapshot isolation through two isolation levels:

REPEATABLE READ uses a transaction-level snapshot. All reads in the transaction see the same committed data from the moment the first query ran. Non-repeatable reads are prevented. Phantom reads from INSERT are also prevented because the snapshot is fixed. Write-skew anomalies involving concurrent non-overlapping writes are still possible.

SERIALIZABLE extends REPEATABLE READ by adding predicate locking — PostgreSQL tracks what data each transaction read and checks whether any concurrent transaction could have logically affected the result. Serialization failures are reported as errors the application must handle by retrying the transaction.

READ COMMITTED does not use snapshot isolation at the transaction level. PostgreSQL takes a fresh snapshot at the start of each individual statement. Two queries in the same transaction can see different committed data if another transaction commits between them.

Vela branches start from a consistent snapshot. Changes in a branch never affect the source. Learn How Vela Works

Why Snapshot Isolation Matters for Production Postgres

The most common pain point snapshot isolation solves is long-running read queries blocking writes — or vice versa. Without MVCC-backed snapshot isolation, a reporting query holding a shared lock would block any concurrent UPDATE on the same table. With snapshot isolation, readers and writers work from their own versions and neither blocks the other.

For production systems this matters in several scenarios:

  • Analytics on the main database. Snapshot isolation lets reporting queries run concurrently with OLTP writes without degrading write throughput.
  • Migration scripts. A migration that reads a large table to backfill data can run under REPEATABLE READ to get a stable view while applications continue writing.
  • Audit and compliance queries. A compliance query that must see a consistent state of the data at a point in time relies on snapshot semantics to ensure the query result is internally consistent.

The cost of snapshot isolation is MVCC overhead: row bloat from retained old versions, and VACUUM work to reclaim space. Systems with high update rates need well-tuned autovacuum to prevent table bloat.

Isolation LevelSnapshot takenDirty readNon-repeatable readPhantom read
READ COMMITTEDPer statementPreventedPossiblePossible
REPEATABLE READPer transactionPreventedPreventedPrevented (in PG)
SERIALIZABLEPer transaction + predicate locksPreventedPreventedPrevented

How Snapshot Isolation Relates to Vela

Snapshot isolation is the mechanism that makes Vela database branches trustworthy as testing environments. A Vela branch starts from a consistent snapshot of the source database. The snapshot is taken at a known transaction boundary, meaning the branch reflects a coherent, fully committed state — not a partially written intermediate.

When you run tests, schema migrations, or RLS policy validation in a Vela branch, you are working with data that is consistent by the same guarantee PostgreSQL provides for REPEATABLE READ transactions. The branch does not diverge from reality because of timing — it is grounded in a specific, stable snapshot.

This also means that changes you make inside the branch — schema changes, data modifications, configuration experiments — are isolated to the branch. The source database snapshot is unaffected. The copy-on-write storage layer keeps the branch divergence contained while sharing unchanged data with the baseline.

Operational Checks

  • Check the default isolation level with SHOW default_transaction_isolation; and confirm it matches your application’s assumptions
  • Review MVCC bloat with SELECT relname, n_dead_tup FROM pg_stat_user_tables ORDER BY n_dead_tup DESC
  • Confirm autovacuum is running and keeping up with write volume to prevent snapshot horizon buildup
  • For long-running reports, consider REPEATABLE READ explicitly rather than relying on READ COMMITTED defaults

Start with How Vela Works, Database Branching, Branch per PR, and the Vela articles library. For adjacent glossary terms, review MVCC (Multi-Version Concurrency Control), Transaction Isolation Levels, Transaction, and Copy-on-Write (COW).

Frequently Asked Questions

What is snapshot isolation?
Snapshot isolation is a database concurrency mechanism where each transaction operates against a point-in-time view of the database captured at transaction start. Reads within the transaction always see the same consistent state, unaffected by concurrent writes that commit after the snapshot was taken.
How does snapshot isolation differ from READ COMMITTED in PostgreSQL?
Under READ COMMITTED, PostgreSQL takes a new snapshot at the start of each statement within a transaction. This means two SELECT statements in the same transaction can return different results if a concurrent transaction commits between them — a non-repeatable read. Snapshot isolation (used by REPEATABLE READ and SERIALIZABLE) takes the snapshot once at transaction start, so the view is stable for the entire transaction.
How does Vela use consistent snapshots for branching?
Each Vela branch starts from a consistent snapshot of the source database at a specific point in time. The branch reflects exactly the committed state at that moment — no partial transactions, no in-flight writes. This is what makes Vela branches production-real rather than approximate copies: the data is consistent by construction, not by luck.
What anomalies does snapshot isolation prevent?
Snapshot isolation prevents dirty reads (seeing uncommitted data from another transaction) and non-repeatable reads (getting different results for the same query within one transaction). It does not prevent all write skew anomalies — for full serializability, PostgreSQL's SERIALIZABLE isolation level adds predicate locking on top of snapshot isolation.
How do you check your current isolation level in PostgreSQL?
Run SHOW transaction_isolation; to see the default for the current session. To see the default for all new connections, check SHOW default_transaction_isolation;. You can set the level for a specific transaction with BEGIN ISOLATION LEVEL REPEATABLE READ; or SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; immediately after BEGIN.