PostgreSQL Write-Ahead Logging (WAL): Crash Recovery and Replication Internals
Learn how PostgreSQL Write-Ahead Logging works, why it exists, and how it enables crash recovery, durability, and replication.
Every durable database eventually faces the same question: what happens if the server crashes in the middle of a write? PostgreSQL solves this problem using Write-Ahead Logging (WAL). It’s one of the most important pieces of the database because it guarantees durability, powers crash recovery, and serves as the foundation for replication.
The Problem WAL Solves
Imagine updating a user’s balance.
UPDATE accounts
SET balance = balance - 100
WHERE id = 1;
At first glance, this seems straightforward. PostgreSQL modifies the row and stores the change on disk.
The problem appears when a crash occurs during the write process.
A database page is usually much larger than a single row. PostgreSQL modifies pages in memory and eventually flushes them to disk. If power is lost while a page is being written, the database can be left in an inconsistent state.
Without some form of recovery mechanism, partially written changes could corrupt data.
A database must be able to recover committed transactions even if it crashes immediately afterward.
Instead of writing data pages first, PostgreSQL writes a description of the change into WAL.
Only after the WAL record is safely stored can the transaction be considered committed.

This simple idea is the foundation of PostgreSQL durability.
Understanding Write-Ahead Logging
The rule behind WAL is surprisingly simple:
Changes must be written to the WAL before the corresponding data page reaches disk.
That’s why it’s called Write-Ahead Logging.
When a transaction modifies data, PostgreSQL generates WAL records describing what changed.
A simplified flow looks like this:
- Transaction modifies a row
- Data page changes in shared buffers
- WAL record is generated
- WAL record is flushed to disk
- Transaction commits
- Data page is written later
The actual table data does not need to reach disk immediately.
Instead, PostgreSQL only guarantees that the WAL has been persisted.
This significantly improves performance because sequential WAL writes are much cheaper than random page writes.

Internally, WAL files are stored inside:
pg_wal/
You can inspect the current WAL location using:
SELECT pg_current_wal_lsn();
The returned value is an LSN (Log Sequence Number), which represents a position within the WAL stream.
WAL and Crash Recovery
Crash recovery is where WAL becomes truly powerful.
Suppose a transaction commits successfully.
BEGIN;
UPDATE products
SET stock = stock - 1
WHERE id = 10;
COMMIT;
The WAL record reaches disk.
The actual table page does not.
A few milliseconds later the server crashes.
Without WAL, that committed transaction would be lost.
With WAL, PostgreSQL performs recovery during startup.
It reads WAL records from the last checkpoint and replays every committed change that was not yet written into data files.
This process is commonly called REDO.
During startup PostgreSQL:
- Reads the latest checkpoint
- Locates WAL records after that checkpoint
- Replays modifications
- Restores a consistent state

Because committed transactions exist inside WAL, PostgreSQL can reconstruct the database even when table pages were never flushed before the crash.
WAL, Checkpoints, and Performance
If PostgreSQL can replay WAL records, why write data pages at all?
Eventually WAL replay would become too expensive.
That’s where checkpoints come in.
A checkpoint forces dirty pages from memory to disk and records a checkpoint location in WAL.
During crash recovery PostgreSQL only needs to replay WAL generated after the latest checkpoint.
You can inspect checkpoint activity:
SELECT *
FROM pg_stat_bgwriter;
Checkpoint frequency is controlled by settings such as:
checkpoint_timeout = 5min
max_wal_size = 1GB
There’s a tradeoff here.
Frequent checkpoints:
- Faster recovery
- More disk writes
- Higher I/O pressure
Less frequent checkpoints:
- Better runtime performance
- Longer crash recovery
Checkpoints reduce recovery work, while WAL preserves committed changes between checkpoints.

Understanding this balance is important when tuning PostgreSQL for production workloads.
WAL as the Foundation of Replication
Before learning WAL internals, I assumed replication worked by copying table data between servers.
PostgreSQL does something smarter.
The primary server continuously generates WAL records.
Replica servers receive those records and replay them.
As WAL is applied, replicas reproduce exactly the same changes occurring on the primary.
The flow looks like:
Primary Database
↓
WAL Stream
↓
Standby Replica
↓
WAL Replay
↓
Consistent Copy
This is known as physical replication.
Because replicas replay WAL rather than executing SQL statements, replication remains efficient even for large workloads.
Useful monitoring query:
SELECT *
FROM pg_stat_replication;
This view shows connected replicas and replication lag.

Once I understood that replication is essentially WAL shipping plus replay, many PostgreSQL replication concepts became much easier to understand.
Important WAL Concepts
Several PostgreSQL internals become easier to understand once WAL enters the picture.
LSN (Log Sequence Number)
Every WAL record receives an LSN.
Examples:
0/16B6A70
0/1704C58
0/1704F18
LSNs help PostgreSQL track:
- Replication progress
- Recovery progress
- Backup consistency
- WAL replay position
WAL Segments
WAL is stored as segment files inside:
pg_wal/
Common filenames look like:
000000010000000000000001
PostgreSQL rotates through these files as new WAL records are generated.
WAL Archiving
Production systems often archive WAL files.
This allows:
- Point-in-time recovery (PITR)
- Disaster recovery
- Backup restoration
The combination of base backups and archived WAL enables recovery to an exact moment in time.
Final Thoughts
WAL is much more than a transaction log. It is the mechanism that allows PostgreSQL to provide durability, recover from crashes, and replicate data across servers.
The key idea is simple: write the description of a change before writing the actual data page. From that single principle PostgreSQL gains reliable crash recovery, efficient disk writes, replication, backups, and point-in-time recovery.
As I continue learning PostgreSQL internals, WAL feels like one of those topics that connects many other concepts together. Checkpoints, replication, backups, recovery, and durability all make more sense once you understand the WAL stream sitting underneath them.