Redis Persistence
RDB snapshots vs AOF logs, the durability/performance trade-off, and how to configure each.
The introduction page mentioned that Redis is volatile by default — a restart with no persistence configured loses everything in memory. This page covers the two mechanisms Redis offers to change that, how they differ, and how to actually configure each.
RDB: point-in-time snapshots
RDB (Redis Database) persistence writes the entire in-memory dataset to a single compact binary file at a point in time. It's configured with save rules in redis.conf, each one meaning "trigger a snapshot if at least N seconds have passed AND at least M keys changed":
save 900 1
save 300 10
save 60 10000
dbfilename dump.rdb
dir /var/lib/redis
This configuration snapshots after 900 seconds if at least 1 key changed, after 300 seconds if at least 10 keys changed, or after 60 seconds if at least 10,000 keys changed — multiple rules coexist so a quiet server still gets occasional snapshots while a very busy one snapshots more often. A snapshot can also be triggered manually:
redis-cli BGSAVE
BGSAVE forks a child process to write the snapshot, relying on the operating system's copy-on-write behavior so the main Redis process keeps serving reads and writes without blocking during the write — the fork itself is nearly instant, but a very high write rate during the snapshot can still cause real memory overhead, since every page a write touches during the fork has to be duplicated rather than shared. (The older SAVE command does the same snapshot synchronously, blocking the server for its entire duration — essentially never the right choice on a live server.)
The trade-off: RDB restores extremely fast (loading one binary file is much quicker than replaying a long log of individual writes), and it produces a single, easy-to-copy-elsewhere file — but any writes since the last snapshot are permanently lost if Redis crashes or is killed before the next one runs. With the save 60 10000 rule above, a crash could lose up to a minute's worth of writes (or fewer than 10,000 keys' worth of changes) that never made it into a snapshot.
AOF: an append-only write log
AOF (Append Only File) persistence takes a different approach: instead of periodic snapshots, it logs every write command as it happens, and reconstructs the dataset on startup by replaying that log from the beginning.
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
appendfsync controls how often the log is actually flushed to disk (as opposed to just handed to the operating system's write buffer), and it's the single most important trade-off in AOF configuration:
appendfsync value |
Behavior | Durability | Performance |
|---|---|---|---|
always |
fsync after every single write | Safest — at most one command lost on a crash | Slowest — every write pays a disk fsync |
everysec (default) |
fsync once per second | Loses at most ~1 second of writes | Good balance, the recommended default |
no |
Let the OS decide when to flush | Loses whatever the OS hadn't flushed yet | Fastest, least durable |
everysec is the right default for the overwhelming majority of use cases — it bounds data loss to roughly a second's worth of writes while avoiding the cost of an fsync on every single command.
AOF rewriting
Because AOF logs every write command ever made, it grows without bound over the life of a busy server — including redundant history like a counter that was incremented a million times, even though only its final value matters for reconstructing state. BGREWRITEAOF compacts the log by rewriting it as the minimal set of commands needed to recreate the current dataset from scratch, the same copy-on-write forking trick BGSAVE uses to avoid blocking the main process:
redis-cli BGREWRITEAOF
Redis can also trigger this automatically based on how much the file has grown since the last rewrite (auto-aof-rewrite-percentage, auto-aof-rewrite-min-size), which is the normal way this happens in practice rather than a manual, remembered step.
Combining both
Since Redis 4.0, aof-use-rdb-preamble yes (the default) makes AOF rewrites store an RDB-formatted snapshot as the start of the rewritten AOF file, followed by any commands logged since — giving RDB's fast restart time together with AOF's tighter durability window, in one file.
Choosing a persistence strategy
| RDB only | AOF only | Both (recommended for durability-sensitive use) | Neither | |
|---|---|---|---|---|
| Data loss window on crash | Minutes (last snapshot interval) | ~1 second with everysec |
~1 second, with RDB-speed restarts | Everything since last restart |
| Restart speed | Fast | Slower (or fast, with the RDB preamble) | Fast | N/A |
| Disk write overhead | Low (periodic only) | Continuous | Continuous | None |
| Good fit for | A pure, fully-rebuildable cache | Any data Redis is the source of truth for | Data that must survive a crash with minimal loss | A cache where losing everything on restart is genuinely fine |
A Redis instance used purely as a cache-aside layer in front of a real database (as on the caching-patterns page) can often run with persistence disabled entirely — every key is trivially rebuildable from the source of truth on a miss, so losing the whole cache on restart just means a temporary wave of cache misses, not lost data.
Common mistakes
- Assuming RDB alone means "durable" — a crash between snapshots loses every write since the last one, which can be minutes of data depending on the configured
saverules. - Setting
appendfsync alwayson a high-throughput application without measuring the cost — it's the safest setting, but it puts a disk fsync on the critical path of every single write. - Never enabling (or triggering) AOF rewriting, letting the file grow to many times the size of the actual dataset it represents.
- Forgetting that
BGSAVE/BGREWRITEAOF's fork needs real free memory headroom — under a high write rate during the fork, copy-on-write can transiently use significantly more memory than the dataset's steady-state size, which matters when sizing a Redis instance close to its memory limit.