The question this answers
After a crash, how does a node rebuild what it knew — and why does the same structure make replication work?
A node that reloads checkpoint C and then applies every log record after C, in log order, reaches a state that is *identical* to the one it would have had at that log position — provided the operations are deterministic and the log is truly ordered and gap-free. Anything acknowledged but not in the log is not recovered, and no amount of replay creates it.
Everything below is bought to hold this sentence. "Strongly consistent" with no scope attached is a slogan, not a guarantee — read what it actually covers, and what it explicitly does not.
A recovering node knows its newest complete checkpoint and the log position that checkpoint corresponds to. It knows the log records it holds locally after that position. It does *not* know whether the log has records beyond what it holds — a node recovering from local disk cannot tell "the log ends here" from "I have not received the rest yet", which is why a recovering replica must ask the current leader rather than declaring itself caught up.
A node knows its own state and the messages that arrived. Everything else is inference from evidence that was already stale. "B has not replied in five seconds" is knowledge; "B is down" is a decision — and usually the bug.
The two ways to remember, and why you need both
Consider a counter at 4,000,001. You can persist the number, or you can persist four million increments. State is compact and fast to load, but it must be written atomically and it destroys history. A log is cheap to append — it is a sequential write, the one thing every storage device is good at — but replaying four million records to learn one number is absurd.
The resolution is the oldest structure in systems: checkpoint the state occasionally, log every change continuously, and recover by loading the newest checkpoint and replaying the log records after it. The checkpoint bounds replay time. The log bounds data loss. Neither alone does both.
The vocabulary changes by layer and the structure does not. A database calls it a write-ahead log plus a checkpoint. A consensus implementation calls it a snapshot plus the The Raft Log: Commit Index, Divergence and Reconciliation suffix. A stream processor calls it state-backend checkpointing plus offsets. An event-sourced application calls it a snapshot plus the event stream. If you have understood it once, you have understood all of them, and the Database domain owns the mechanics of doing it well on one machine.
Write-ahead is the ordering rule that makes it sound
The whole scheme rests on one ordering constraint: the log record must be durable before the change it describes is applied to the main structure. That is the "write-ahead" in write-ahead logging, and reversing it breaks recovery — a crash between applying and logging produces a state whose history nobody has.
From that constraint two useful properties follow. Recovery is *idempotent*: replaying a record whose effect is already present must be harmless, which is why records are keyed by a monotonically increasing position and application is conditional on that position. And recovery is *bounded*: you only ever replay from the checkpoint forward, so replay time is a function of checkpoint frequency, not of the system’s age.
The Database domain owns how this is implemented — record formats, group commit, fuzzy checkpoints, the interaction with the buffer pool. What belongs here is the observation that the constraint is about order and durability of the record relative to the change, and that this is a property you can state and check for any system that claims to be recoverable, at any layer.
[recover] latest checkpoint = 000900 (14.2 GB, written 09:41:07) [recover] local log holds 000901..001247 [recover] replaying 347 records ... [recover] record 001102 already applied (position <= state position) — skipped, no-op [recover] replay complete, state position = 001247, 1.9s [recover] asking leader for records beyond 001247 ... [recover] leader log ends at 001260 — fetching 13 records <-- the local log was NOT the end
The same structure is the replication protocol
Here is the observation this lesson exists for. Recovery and replication are the same operation with a different destination. Recovery replays the log into the same node after a crash. Replication ships the log to a different node and replays it there. In both cases the receiving state machine starts from a known position and applies an ordered sequence of deterministic changes.
That is not an analogy — it is literally how the systems are built. Postgres streams the WAL to standbys. Raft *is* a replicated log whose commit rule decides which prefix everyone must apply. Kafka replicas fetch the leader’s log and apply it. When a new replica joins with no state at all, it does not get a special protocol: it gets a checkpoint transfer followed by the log from that checkpoint’s position, which is the recovery procedure with a network hop inserted.
This explains why log-based systems dominate this space. Choosing a log as your durability mechanism gets you replication, point-in-time recovery, and change data capture from the same artefact, because all three are "read the ordered record of changes from some position". Choosing to persist state only gets you none of them. It is also why The Log Is Not a Queue and A Topic Is Not One Log: Ordering Lives Inside a Partition keep reappearing in this domain: the log is the primitive that makes several otherwise-separate problems into one.
The catch is determinism. Replay reproduces the original state only if applying a record is a pure function of the record and the prior state. A record saying "set expires_at to now() + 1 hour" replays to a different value; the log must therefore record the *computed result*, not the instruction that computes it. Any non-determinism — wall-clock reads, random values, external calls — has to be resolved at record time and written down, or the recovered state diverges from the state you lost.
- Replication = recovery, with the replay happening on another machine.
- Bootstrapping a new replica is checkpoint transfer plus log from that position — not a separate mechanism.
- Log records must carry results, not instructions, wherever the instruction is non-deterministic.
- One log artefact yields durability, replication, point-in-time recovery and change capture at once.
- The commit rule — which log prefix everyone must apply — is where consensus enters; see The Raft Log: Commit Index, Divergence and Reconciliation.
Choosing the checkpoint interval is choosing your recovery time
Checkpoint frequency is a straight trade with exactly two sides. Frequent checkpoints mean short replay and therefore short recovery, at the cost of steady I/O and, for large state, a visible latency bump while the checkpoint is taken. Infrequent checkpoints are cheap in steady state and expensive exactly once — during an incident, when you are watching a node replay for forty minutes and can do nothing about it.
The asymmetry is what people get wrong. Checkpoint cost is paid continuously and is easy to see on a graph; replay cost is paid rarely and only when you can least afford it. Teams therefore drift toward long intervals, because the graph rewards it and nothing punishes it until an incident. The number to hold is not the checkpoint interval but the resulting worst-case replay time, and that number should be measured rather than estimated — by actually restarting a node with a full log suffix and timing it.
The second trap is log retention. Truncating the log before the checkpoint that covers it makes the state unrecoverable — an operational mistake with no gradual warning, only a cliff. Correspondingly, retaining log beyond the oldest checkpoint any *replica* might still need is what lets a lagging replica catch up without a full state transfer; truncate too eagerly and a replica that was thirty seconds behind now needs a fourteen-gigabyte snapshot copy.
| Interval | Steady-state cost | Recovery time | Log retention needed |
|---|---|---|---|
| Every 30 secondstypical | High and constant I/O; latency bumps on large state | Seconds | Small |
| Every 10 minutestypical | Moderate, usually invisible | Tens of seconds to minutes | Moderate |
| Every hourtypical | Low | Minutes to tens of minutes, exactly during an incident | Large |
| Never (log only)protocol | None | Grows without bound with system age | Everything, forever |
Key points
- Recovered state = newest checkpoint + every log record after it, applied in order.
- Write-ahead is the ordering rule that makes it sound: the record is durable before the change is applied.
- Replay must be idempotent and deterministic, which means records carry computed results, not instructions.
- Replication is the same replay with the destination on another machine — that is why log-based designs get replication for free.
- Checkpoint interval directly sets worst-case recovery time; measure that number rather than estimating it.
- Truncating the log ahead of the checkpoint that covers it, or ahead of a lagging replica’s position, are two different cliffs with no warning.
The chain, answered
Every field here is required, which is why no lesson in this domain can recommend a design without naming what an operator sees when it fails, what survives the partition, what repairs it afterwards, and the simpler thing to consider first.
- • Every change is appended to an ordered log with a monotonically increasing position, and made durable there first.
- • The change is then applied to the in-memory or on-disk main structure.
- • Periodically, a checkpoint records the complete state together with the log position it corresponds to.
- • Log records older than the newest checkpoint — and older than any consumer or replica still needs — may be truncated.
- • On restart, the node loads the newest complete checkpoint and replays every log record after that position, skipping records already reflected in the state.
- • A replica performs the same procedure against a checkpoint transferred over the network and a log stream fetched from the leader.
- • A crash occurs mid-checkpoint, leaving a partial checkpoint that must be recognisable as incomplete rather than loaded.
- • The log has a gap because a record was lost, making everything after it unreplayable.
- • A record encodes a non-deterministic instruction, so replay produces a different state from the original.
- • The log is truncated past the point a replica or a checkpoint still needs.
- • The recovering node’s local log is shorter than the true log, and the node declares itself caught up.
- • Recovery that never finishes: a node restarts and spends forty minutes replaying, while operators watch a process at 100% CPU with no progress metric. The checkpoint interval was set years ago and the write rate has grown tenfold since.
- • Divergent replay: a recovered node’s values differ subtly from what it had — timestamps shifted, expiries recomputed. Nothing errors; a downstream consistency check catches it later, if one exists.
- • Snapshot storm: a replica that fell slightly behind is forced into a full state transfer because the log it needed was truncated. The transfer saturates the network and pushes other replicas behind, which then need transfers too.
- • Silent partial checkpoint: a checkpoint written during a crash is loaded as if complete; the node comes up with state that never existed and serves it happily.
- • Log growth to disk-full: checkpointing has been failing for days, so nothing can be truncated. The first symptom is the disk filling, not the failed checkpoints.
- • None is needed to checkpoint a single node — the state is entirely local, which is what makes single-node recovery cheap.
- • Deciding which log prefix is committed *is* consensus when several nodes must agree; that decision is the subject of The Raft Log: Commit Index, Divergence and Reconciliation, not of checkpointing.
- • Truncation is a coordinated decision: the safe truncation point is the minimum over every consumer and replica that might still need the log, so one lagging replica pins retention for everyone.
- • Capturing a checkpoint of state that spans several nodes is a genuinely different problem, and the subject of A Consistent Cut, Without Stopping the World.
- • Any change that reached the log durably is recoverable; anything acknowledged before reaching the log is not, and this is exactly the boundary Acknowledged, Durable, Replicated: Three Different Things describes.
- • A partial checkpoint is discarded and the previous complete one is used, so a crash during checkpointing costs replay time rather than correctness.
- • Replay is idempotent, so a crash *during recovery* is safe: restart and replay again from the same checkpoint.
- • The recovered state is a legal prior state of the system, not an arbitrary one — the log position tells you exactly which prior state it is.
- • Detect: a node that is up but not serving is usually replaying; expose replay progress as a position and an estimated remaining count, not as a log line.
- • Contain: keep the node out of the serving set until its state position has caught up, or it will serve stale reads that look like a consistency bug.
- • Recover: load newest complete checkpoint, replay forward, then ask the leader for anything beyond the local log end.
- • Reconcile: after catching up, verify the state position against the leader’s commit position rather than against the local log end.
- • Verify: rehearse it. A restart drill that measures actual replay time is the only way the checkpoint interval stays connected to reality.
- • Replay progress during startup — records remaining and estimated time — which turns an opaque forty-minute wait into a known one.
- • Time since last successful checkpoint, alerted well before the log fills the disk. Failed checkpointing is silent until it is catastrophic.
- • Log size on disk and the current safe truncation point, together, so a pinning consumer is visible before the disk is.
- • Distance between each replica’s applied position and the leader’s commit position, in records rather than in bytes.
- • Measured cold-start time from a real drill, tracked over time — it grows silently as write volume grows.
- • Any stateful service that must survive restarts without losing what it knew — which is nearly all of them.
- • Systems that need replication, point-in-time recovery or change capture, because one log artefact provides all three.
- • Large in-memory state, where reloading from a checkpoint is the difference between a ten-second and a ten-hour restart.
- • Genuinely derivable state: if a cache can be rebuilt from a source of truth in seconds, checkpointing it is machinery protecting nothing.
- • Very small state, where writing the whole state on every change is simpler and fast enough — the log adds a moving part for no benefit.
- • Workloads whose apply step is inherently non-deterministic and cannot be made otherwise; forcing them into a replay model produces confident, wrong recoveries.
- • Rebuild from the source of truth instead of recovering, when one exists upstream — a stream processor can often reset to an offset and recompute rather than checkpointing state at all.
- • Write full state on every change, when the state is small. Simpler, obviously correct, and the log is unnecessary.
- • Keep no state at all: push it into a database that already solved this — the stateless-service default, which removes the problem rather than managing it.
- • Snapshot-only with a longer accepted data-loss window, when the changes since the last snapshot are cheaply reproducible from upstream.
Checkpoint often and pay always; checkpoint rarely and pay during the incident
[recover] latest checkpoint = 000900 (14.2 GB, written 09:41:07) [recover] local log holds 000901..001247 [recover] replaying 347 records ... [recover] record 001102 already applied (position <= state position) — skipped, no-op [recover] replay complete, state position = 001247, 0.2s [recover] asking leader for records beyond 001247 ... [recover] leader log ends at 001260 — fetching 13 records <-- the local log was NOT the end
| Steady-state cost | Recovery time | Log retention needed | |
|---|---|---|---|
| Every 30 secondstypical | High and constant I/O; latency bumps on large state | Seconds | Small |
| Every 10 minutestypical | Moderate, usually invisible | Tens of seconds to minutes | Moderate |
| Every hourtypical | Low | Minutes to tens of minutes, exactly during an incident | Large |
| Never (log only)protocol | None | Grows without bound with system age | Everything, forever |
What people believe, and what is true
A checkpoint is a backup.
A checkpoint is for restarting this node. A backup is for the case where this node and its disks no longer exist, and lives somewhere else with a separate retention and restore path.
Longer checkpoint intervals are just a small performance saving.
They are a direct multiplier on recovery time, paid during an incident. The saving is visible daily; the cost is invisible until it is the outage.
Replay always gives back the same state.
Only for deterministic operations. A record that says "expire in one hour" replays to a different value than it originally produced.
Replication and recovery are separate features.
They are the same replay against different destinations. That is why log-based systems get replication almost as a side effect and state-only systems do not.
Go deeper
Only the levels this lesson can honestly fill — a missing level is a claim nobody had.
Overview
Save the state occasionally; log every change continuously. To recover, load the newest save and replay the changes after it. The save bounds how long recovery takes; the log bounds how much you lose.
Practical
Measure real cold-start time in a drill rather than trusting the checkpoint interval. Alert on time-since-last-successful-checkpoint, not on disk usage. Keep log retention above the slowest replica’s needs so a small lag never escalates into a full state transfer. Make sure every log record stores computed values, not instructions that recompute.
Advanced
The reason this structure is everywhere is that a log is a *total order over changes*, and a total order is exactly what both recovery and replication need. Once you have committed to one, you can hand the same artefact to a replica, a point-in-time restore, a change-data-capture consumer and an audit trail without designing anything further. The remaining hard question — which prefix of the log is committed, when several nodes hold different suffixes — is not a storage problem at all. It is Total Order Broadcast Is Consensus Wearing a Different Hat, and consensus is what answers it.
Apply it
- 💬 Why not just checkpoint on every change and skip the log?
- 💬 A node restarts and takes forty minutes to come back. What do you change, and what do you measure first?
- 💬 Explain why a log-based system gets replication almost for free.
- 💬 What breaks if a log record says "set expiry to now plus one hour"?