Backup and Restore
Redis keeps its entire dataset in memory, which is exactly why it’s fast — and exactly why a crash, an accidental restart, or a bad deploy can wipe out everything unless the data has also been written to disk. “Backup and restore” in Redis covers two related but distinct tools: whole-database snapshotting to a file you can copy elsewhere and reload later, and single-key export/import using the DUMP and RESTORE commands. Understanding both — and how each interacts with expiration and existing keys — is essential for running Redis anywhere data loss actually matters.
Overview / How it works
Redis’s primary backup mechanism is the RDB (Redis Database) file, a compact, point-in-time binary snapshot of every key in the dataset. You can trigger one in two ways. SAVE performs the snapshot synchronously on the main thread: because Redis is single-threaded, every other command is blocked from running until the snapshot finishes writing to disk. On a large, busy dataset this can freeze the server for seconds, so SAVE is rarely what you want outside of maintenance windows. BGSAVE instead forks a child process; the parent process (still serving your normal traffic) shares the same memory pages with the child via the operating system’s copy-on-write mechanism, and only pages that are modified after the fork get duplicated. The child writes a full snapshot to a temporary file and atomically renames it over the configured RDB file (dump.rdb by default) when it finishes. This is why BGSAVE is non-blocking for clients but still costs CPU and memory overhead from the fork and the copy-on-write pages.
Restoring from an RDB file isn’t a command you run against a live server — it’s an operational step. Redis only loads an RDB file at startup, before it accepts any client connections: it reads the file from the directory and filename configured by the dir and dbfilename settings, reconstructs every key, hash, list, set, and sorted set exactly as they were at snapshot time, and only then starts listening. To restore an older snapshot, you stop the server, replace the RDB file in that directory with your backup copy, and start the server again. If AOF (Append Only File) persistence is also enabled, Redis prefers the AOF for reconstructing state at startup, since it can replay every individual write and loses less data than a periodic snapshot — but that’s a tradeoff of durability against restore speed and file size, not a reason to skip RDB backups entirely; production Redis deployments often keep both.
For backing up or moving a single key without touching the whole dataset, Redis provides DUMP and RESTORE. DUMP serializes a key’s value into Redis’s internal binary wire format — the same format used internally for replication and AOF rewrites — appended with a 2-byte RDB version and an 8-byte CRC64 checksum. RESTORE takes that exact byte string back and recreates the key. The checksum means a corrupted or truncated payload is rejected with an error rather than silently creating a broken key. Because the payload is binary (it isn’t printable text), a full DUMP-then-RESTORE round trip is normally done by a client library that can capture and pass along the raw bytes, not by retyping it at the redis-cli prompt by hand.
Syntax
SAVE
BGSAVE
LASTSAVE
BGREWRITEAOF
DUMP key
RESTORE key ttl serialized-value [REPLACE]
CONFIG GET dir
| Command | Purpose | Time complexity |
|---|---|---|
SAVE |
Synchronous, blocking RDB snapshot of the whole dataset | O(N), N = total number of keys; blocks the server for the duration |
BGSAVE |
Non-blocking RDB snapshot via a forked child process | O(N) in the background; forking itself is roughly O(1) on most systems |
LASTSAVE |
Unix timestamp of the last successful RDB save | O(1) |
BGREWRITEAOF |
Rewrites the AOF file in the background to compact it | O(N), runs in a forked child process |
DUMP key |
Serializes a single key’s value to a binary string | O(1) for a string; O(N) for lists, hashes, sets, and sorted sets, where N is the number of elements |
RESTORE key ttl serialized-value [REPLACE] |
Recreates a key from a payload previously produced by DUMP |
O(1) for a string; O(N) for aggregate types, same as DUMP |
CONFIG GET dir |
Reads the directory Redis writes its RDB/AOF files to | O(N) where N is the number of matching config parameters (here effectively O(1)) |
- ttl in
RESTOREis in milliseconds, not seconds —0means the restored key has no expiration. - REPLACE is required if a key with that name already exists; without it,
RESTORErefuses to overwrite anything. dirplusdbfilename(defaultdump.rdb) together determine where the RDB file lives on disk.
Examples
Example 1: Triggering a background snapshot and checking when it finished
SET user:1001:name "Ada"
SET user:1001:email "ada@example.com"
BGSAVE
LASTSAVE
Output:
OK
OK
Background saving started
(integer) 1754800000
The two SET commands write ordinary keys. BGSAVE forks a child process and returns immediately with a confirmation that the save has started — it does not wait for the snapshot to finish. LASTSAVE returns the Unix timestamp of the most recently completed save; on a real server, calling it immediately after BGSAVE may still show the timestamp of the previous snapshot rather than the one that just started, since the fork’s write can take a moment.
Example 2: A blocking foreground save, and finding where it’s written
SET session:abc123 "active"
SAVE
CONFIG GET dir
Output:
OK
OK
1) "dir"
2) "/data"
SAVE writes the RDB file synchronously on the main thread and only returns OK once the file is fully on disk — no other client command can run in the meantime. CONFIG GET dir confirms the directory Redis is configured to write dump.rdb into (the actual value depends on your server’s configuration); that directory is exactly where you’d look to copy the file off-box for a real backup, or where you’d drop a replacement file before restarting the server to restore one.
Example 3: Backing up a single key with DUMP
SET config:app:theme "dark"
DUMP config:app:theme
Output:
OK
"\x00\x84dark\x0b\x00\xf3\x02\xb7\xbb\x9a\x86\x00\xe0"
DUMP returns the key’s value serialized as a binary string — mostly non-printable bytes, which redis-cli displays using backslash escapes. That exact byte string is what you’d hand to RESTORE to recreate the key, either on the same instance under a different name or on a completely different Redis instance, which makes DUMP/RESTORE a handy way to migrate or clone individual keys without exporting the whole dataset. Because the payload is binary, this round trip is normally driven by a client library that can pass the exact bytes back, rather than typed by hand:
RESTORE config:app:theme:backup 0 PAYLOAD_FROM_DUMP
Here PAYLOAD_FROM_DUMP stands in for the literal bytes DUMP returned; a ttl of 0 means the restored copy has no expiration.
How it works step by step
When you run BGSAVE: (1) Redis’s main thread calls fork(), creating a child process that shares the parent’s memory pages. (2) The parent immediately returns Background saving started and keeps serving client commands normally. (3) The child walks every key in every database and writes a compact binary representation to a temporary RDB file, relying on copy-on-write so that writes happening in the parent during this time don’t corrupt the child’s view of the data — instead the OS duplicates just the pages that change. (4) When the child finishes, it atomically renames the temp file over the configured RDB file and exits; the parent updates the value LASTSAVE will report. On restart, Redis reads that RDB file from disk before opening its client port, reconstructing every key exactly as it existed at snapshot time — any writes made after the last successful save and before the crash are gone, which is the core tradeoff of RDB-only persistence.
Common Mistakes
Using SAVE instead of BGSAVE in production. SAVE blocks every client until the snapshot finishes writing to disk, which on a large dataset can mean multi-second stalls for every connected application. Use BGSAVE for on-demand snapshots against a live server, and reserve SAVE for situations where the server isn’t handling traffic yet.
Calling RESTORE on a key that already exists without REPLACE. Redis checks for a naming conflict before it even validates the payload, and refuses to overwrite silently:
SET config:app:theme "light"
RESTORE config:app:theme 0 PAYLOAD_FROM_DUMP
OK
(error) BUSYKEY Target key name already exists.
Add REPLACE if overwriting is actually intended: RESTORE config:app:theme 0 PAYLOAD_FROM_DUMP REPLACE.
Treating a single RDB snapshot as a complete backup strategy. Every write made after the last BGSAVE and before a crash is lost — if your save points are minutes or hours apart, that’s the size of the data-loss window. Pairing RDB with AOF, or snapshotting more frequently, narrows that window; assuming “we have an RDB file” automatically means “we have current data” is a common and costly mistake.
Leaving the only copy of dump.rdb on the same disk as the live server. A backup that lives next to the data it’s backing up doesn’t protect against a disk failure, a bad deploy that deletes the volume, or a compromised host. Copy RDB files to separate storage on a schedule, not just to another path on the same machine.
Best Practices
- Prefer
BGSAVEoverSAVEfor on-demand snapshots against a server that’s serving traffic. - Copy the RDB file to storage outside the Redis host (object storage, a separate volume, another region) on a regular schedule, not just at snapshot time.
- Combine RDB snapshots with AOF if you need to minimize the data-loss window — RDB alone only protects up to the last completed save.
- Periodically test an actual restore (stop a test instance, drop in a backup RDB file, start it, verify the data) rather than assuming a file that exists is a file that works.
- Use
DUMP/RESTOREfor moving or cloning individual keys between instances instead of exporting and reloading the entire dataset. - Remember
RESTORE‘s ttl argument is in milliseconds, and thatREPLACEis required to overwrite an existing key. - Check
LASTSAVEor therdb_last_save_timeandrdb_last_bgsave_statusfields fromINFO persistenceto confirm backups are actually succeeding, rather than assuming a scheduledBGSAVEsilently worked.
Practice Exercises
- Set three keys representing a small shopping cart (for example
cart:5001:item:1,cart:5001:item:2,cart:5001:total), trigger a background snapshot, and useLASTSAVEto confirm you can see when the save actually completed relative to when you issuedBGSAVE. - Use
DUMPon one key, then work out the exactRESTOREcommand you’d need to recreate that same value under a new key name on the same instance, including the correct ttl argument for “no expiration.” - Run
CONFIG GET diragainst your local instance and describe, step by step, exactly what you’d do to restore an olderdump.rdbbackup — including why the server must be stopped first.
Summary
- RDB snapshots are point-in-time backups of the whole dataset, written to
dump.rdbbySAVE(blocking) orBGSAVE(non-blocking, via a forked child using copy-on-write). - Restoring an RDB file is an operational step, not a command — replace the file in the configured
dirand restart the server, which loads it before accepting connections. DUMPandRESTOREserialize and recreate a single key’s value, useful for migrating or cloning individual keys between instances.RESTORE‘s ttl argument is in milliseconds, andREPLACEis required to overwrite an existing key or you’ll get aBUSYKEYerror.- RDB-only backups lose everything written since the last completed snapshot; pair with AOF and off-host copies for real durability.
- Use
LASTSAVEorINFO persistenceto verify backups are actually completing, not just assume they are.
