Question: Write-ahead log
Why does Postgres write so much WAL?
Answered in the first paragraph. Last updated .
Because the log is not a record of your row changes. The first time a page is touched after a checkpoint, the whole page goes into the log, not the few bytes that changed. A workload that touches many pages lightly therefore produces far more log than its update count suggests, and the size of the multiplier is decided by how often checkpoints run. Index maintenance and page-leaving updates are the other two large contributors.
The checkpoint multiplier
Those whole-page copies exist because a crash can leave a page half written, and a record describing a row change cannot repair a page that is internally inconsistent. Writing the page in full at least once per checkpoint cycle guarantees there is always a known-good starting point. Full page images covers the mechanism.
The consequence is counter-intuitive. Checkpointing more often makes each one cheaper and makes the total log volume larger, because every cycle starts a fresh round of first touches. Spreading checkpoints further apart cuts the volume noticeably and lengthens crash recovery in exchange. That is the trade, and on a write-heavy cluster it is usually the single largest lever on log volume.
Compressing those images is supported and is the cheap half of the same win, with a choice of algorithms so the processor cost can be traded against the byte count.
The workload half
An update that changes an indexed column has to write index entries as well as the row, so the number of indexes on a hot table multiplies its log volume directly. An update whose new version no longer fits on the same page loses the cheap path entirely, which is what HOT updates and fillfactor is about, and a table that has been widened is the usual way a workload falls off it.
Maintenance writes too. Vacuum logs what it removes, and a table that accumulates and clears large numbers of dead rows pays for both halves, which is one more reason autovacuum and table bloat is worth reading before tuning anything here.
Measure before changing settings. The log statistics view gives the volume and the number of full-page writes, which is what separates the checkpoint cause from the workload cause. On PostgreSQL 18 note that the reset call clears only part of it and succeeds while doing so, so a dashboard built on a reset-and-compare loop reports nonsense until the query is updated. If the concern is disk rather than throughput, retention rather than volume is the thing to look at, in why pg_wal fills up.