Redis persistence is one of those settings nobody thinks about until a server restarts and half the data is gone, or all of it. Redis keeps the dataset in memory, and what survives a crash depends entirely on two mechanisms: RDB snapshots and the append-only file (AOF). They protect against different things, cost different amounts, and the defaults may not match what your application assumes. This guide walks through what each one really guarantees, based on the Redis persistence documentation.
The four options
- RDB: point-in-time snapshots of the whole dataset at intervals.
- AOF: a log of every write command, replayed on startup.
- RDB + AOF: both in the same instance.
- No persistence: sometimes used for pure caches.
The documentation's own recommendation is short: use both if you want data safety comparable to PostgreSQL; RDB alone if you can live with losing a few minutes of data in a disaster. It discourages AOF alone, because an occasional RDB snapshot is useful for backups, faster restarts and in case of bugs in the AOF engine.
RDB snapshots: compact, fast to restart, but you lose minutes
With RDB, Redis forks a child process, the child writes the dataset to a temporary file, and that file atomically replaces the old dump.rdb. The parent keeps serving clients and does no disk I/O itself. The default configuration looks like this:
# defaults when no "save" line is given (redis.conf, Redis 7.4)
# save 3600 1 300 100 60 10000
dbfilename dump.rdb
stop-writes-on-bgsave-error yes
Without an explicit save line, Redis snapshots after an hour if at least 1 key changed, after 5 minutes if at least 100 changed, and after 60 seconds if at least 10,000 changed. On a quiet system that can mean an hour between snapshots. Whatever was written after the last snapshot is lost if Redis stops without a clean shutdown: a crash, an OOM kill, a power cut.
What RDB is good at: a single compact file, ideal for backups and for copying offsite, and faster restarts with big datasets than AOF. And a detail that surprises people: stop-writes-on-bgsave-error yes is the default, so if snapshots are enabled and the last background save failed (full disk, permissions), Redis stops accepting writes. That is deliberate, but it turns a disk problem into an application outage.
The cost of fork()
Both RDB snapshots and AOF rewrites use fork(). The documentation warns that fork can take time with a big dataset and may stop Redis serving clients for some milliseconds, or even for a second if the dataset is very big and the CPU is slow. Copy-on-write also means pages modified during the save are duplicated, so a write-heavy instance needs memory headroom while a snapshot runs. We cover the memory side in our guide to Redis OOM and maxmemory. latest_fork_usec in INFO stats shows how long the last fork took.
AOF: much more durable, with a choice of fsync
With appendonly yes, every command that changes the dataset is appended to the log. The key setting is appendfsync:
always: fsync after every batch of writes. The documentation calls it "very very slow, very safe", though it does group commits from parallel clients.everysec: fsync once a second, in a background thread. This is the default and the recommended policy: fast, and you may lose about one second of writes in a disaster.no: leave flushing to the operating system. The fastest and least safe; Linux typically flushes every 30 seconds, depending on kernel tuning.
A typical AOF configuration:
appendonly yes
appendfsync everysec # default; alternatives: always, no
appenddirname "appendonlydir"
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-use-rdb-preamble yes
aof-load-truncated yes
The log grows with every write, so Redis rewrites it in the background: auto-aof-rewrite-percentage 100 triggers a rewrite when the AOF has grown by 100% since the last rewrite, as long as it is at least auto-aof-rewrite-min-size. You can also start one manually with BGREWRITEAOF. With aof-use-rdb-preamble yes, the rewritten base is stored in RDB format, which loads faster.
Since Redis 7.0 the AOF is no longer a single file. It is a directory (appendonlydir by default) with one base file, one or more incremental files and a manifest that ties them together. That matters for backups, below. The documentation lists two costs only for versions before 7.0: writes arriving during a rewrite were buffered in memory, and they were written to disk twice.
When the AOF is damaged
If Redis crashed mid-write or the disk filled up, the last command in the AOF may be truncated. With aof-load-truncated yes (the default), Redis discards the incomplete command, logs a warning and starts. If the file is corrupted in the middle, Redis refuses to start. The documentation advises making a copy and running redis-check-aof without --fix first, to see where the problem is: letting the tool fix it may discard everything from the invalid part to the end of the file.
One more useful property: if someone runs FLUSHALL by mistake, and no rewrite has happened since, you can stop the server, remove the last command from the AOF and start Redis again with the data intact. That only works if you act before the next rewrite.
Switching from RDB to AOF without losing data
This is where people lose data. If you simply set appendonly yes in redis.conf and restart, Redis starts with AOF enabled, and when AOF is on it loads the AOF rather than the RDB file, because the AOF is assumed to be the more complete one. The documentation warns explicitly that not following the procedure "can result in data loss". The safe way on a live server:
- Back up the latest
dump.rdband copy it somewhere safe. - Enable AOF on the running server and let it build the AOF from memory:
redis-cli CONFIG SET appendonly yes redis-cli INFO persistence # wait: aof_rewrite_in_progress:0, aof_last_bgrewrite_status:ok redis-cli CONFIG REWRITE # make the change survive a restart - Make sure
redis.confmatches the running configuration. If you skip this, the next restart brings back the old configuration. - Before any restart, check that the AOF rewrite finished (
aof_rewrite_in_progressandaof_rewrite_scheduledat 0,aof_last_bgrewrite_statusok). After restarting, compare the number of keys with what you had before.
Persistence is not a backup. RDB and AOF protect you from a restart or a crash on the same machine. They don't protect you from losing the disk, the server or the region, and an AOF faithfully records a bad bulk delete along with everything else. Copy snapshots off the machine.
Backups and monitoring
- RDB files are safe to copy while Redis runs, because a finished RDB is never modified and the new one is renamed into place atomically. The documentation suggests hourly and daily copies, deleting old ones with a scheduled job, and transferring at least one snapshot a day outside the data center or at least outside the machine.
- AOF backups since 7.0 need care. Copying the AOF directory during a rewrite can produce an invalid backup. The documented approach is to set
auto-aof-rewrite-percentage 0, confirm no rewrite is in progress, copy (or hard-link) the files in the AOF directory, and then restore the previous value. - Redis 8.10 adds a
BACKUPcommand family (BACKUP START,SEAL,LIST,CLEANUP) that produces a restorable base-plus-increment backup without manually pausing AOF rewrites. If you are on an older version, or on Valkey, check which commands your server actually supports. - Test the restore. A snapshot nobody has loaded is a hope. Our guide to backup and restore testing applies to Redis too.
For monitoring, these INFO fields are the ones to alert on:
redis-cli INFO persistence | grep -E \
'rdb_last_bgsave_status|rdb_last_save_time|rdb_changes_since_last_save|aof_enabled|aof_last_write_status|aof_last_bgrewrite_status'
redis-cli INFO stats | grep latest_fork_usec
A rdb_last_bgsave_status or aof_last_write_status other than ok, or a rdb_last_save_time that is far in the past while rdb_changes_since_last_save keeps growing, means your persistence is not doing what you think.
Key takeaways
- RDB alone can lose minutes of writes, up to an hour on a quiet system with the default save points.
- AOF with
appendfsync everysec(the default) limits loss to about a second; the documentation recommends combining it with RDB. - Both rely on
fork(): plan memory headroom and watchlatest_fork_usec. - Never switch to AOF by editing the config and restarting; enable it live, wait for the rewrite, then persist the config.
- Persistence is not a backup: copy snapshots off the machine and test restores.