← index

Redis RDB Format Visualizer

Modelled on src/rdb.c and src/rdb.h, Redis 7.2.14. Listpack, intset and CRC64 layouts follow listpack.c, intset.c and crc64.c from the same release.

An RDB file is a header, a run of opcodes, one record per key and an 8-byte checksum. Build a keyspace below and every byte a 7.2.14 server would write for it appears on the right, in order. The bytes are real: the download is a loadable .rdb, and the type byte for each value is chosen the way rdbSaveObjectType chooses it, so a small hash gets a listpack and a large one gets a hash table.

Add a key

rdb.c:1125 rdbSaveKeyValuePair

Keyspace

db 0 · empty

No keys. Redis skips an empty database entirely — no SELECTDB opcode is written for it (rdb.c:1310).

Save trace

rdb.c:1376 rdbSaveRio

RDB byte stream

0 bytes

FF magic and opcode FF length or encoding prefix FF payload FF end of file FF CRC64

Opcodes

rdb.h:103–113

The complete 7.2.14 list. An opcode is read where a value type byte would otherwise be, so anything from 245 upward is an instruction rather than a type (rdbIsObjectType covers 0–7 and 9–21, rdb.h:100).

hexdecnamewhat follows it
F5245FUNCTION2One function library's source, as a string. One opcode per library (rdb.c:1279).
F6246FUNCTION_PRE_GA“Old function library data for 7.0 rc1 and rc2” (rdb.h:104).
F7247MODULE_AUXModule id, a UINT sub-opcode and a when-marker, module data, then an EOF sub-opcode (rdb.c:1216).
F8248IDLEA length-encoded idle time in seconds. Written only under an LRU maxmemory policy (rdb.c:1136–1140).
F9249FREQOne raw byte, the LFU counter. Written only under an LFU policy (rdb.c:1144–1152).
FA250AUXTwo strings: field name, then value.
FB251RESIZEDBTwo lengths: key count, then how many of them have an expiry.
FC252EXPIRETIME_MS8 bytes, little-endian, an absolute Unix time in ms.
FD253EXPIRETIME4 bytes read as an int32, in seconds (rdb.c:134). Still read, never written by 7.2 — rdb.c:1130 always uses FC.
FE254SELECTDBA length-encoded database number.
FF255EOFNothing. The 8-byte checksum follows.

Per-key metadata precedes the value type byte, not the key: FC <8 bytes> then F8/F9 if the policy asks for them, then the type byte, then the key, then the value (rdb.c:1129–1158). RDB_OPCODE_SLOT_INFO does not exist in 7.2.

Length encoding

rdb.c:172 rdbSaveLen

The top two bits of the first byte say how to read the rest.

first bytemeaning
00xxxxxxThe length is the low 6 bits. One byte total, covering 0–63.
01xxxxxx14-bit length: low 6 bits are the high half, the next byte the low half.
10000000RDB_32BITLEN (0x80). A 32-bit length follows, big-endian — htonl, unlike every other multi-byte field in the format.
10000001RDB_64BITLEN (0x81). A 64-bit big-endian length follows. Taken only when the length exceeds UINT32_MAX (rdb.c:196–199).
11xxxxxxRDB_ENCVAL. Not a length: the low 6 bits name a special encoding for the string that follows.

String encodings

rdb.c:442 rdbSaveRawString

A string is tried as an integer first, then as compressed, then stored verbatim.

prefixlayout
C0INT8: one signed byte.
C1INT16: two bytes, little-endian.
C2INT32: four bytes, little-endian.
C3LZF: compressed length, then original length, both length-encoded, then the payload (rdb.c:345–361).
—Otherwise a length, then that many raw bytes.

Integer encoding is attempted only when the string is at most 11 bytes (rdb.c:447) and parses as a canonical integer — string2ll rejects leading zeros, -0 and trailing text (util.c:438). Compression is attempted only when rdbcompression is on and the string is longer than 20 bytes (rdb.c:457); this page never compresses, so a long string here shows the verbatim form.

How the type byte is chosen

rdb.c:661 rdbSaveObjectType

The type byte names the encoding on disk, not the user-visible type. A small collection is one packed blob; a large one is written element by element. The ziplist types 10, 12 and 13 are still read by 7.2 but nothing writes them any more.

valuetype bytewritten whenpayload
String0 STRINGalwaysOne string.
List18 LIST_QUICKLIST_2always — there is no other list branch (rdb.c:665–668)Node count, then per node a container flag (2 = packed) and the node's listpack as a string.
Set11 SET_INTSETevery member parses as an integer and there are at most 512 (set-max-intset-entries)An intset blob as a string.
Set20 SET_LISTPACKat most 128 members, none longer than 64 bytesA listpack as a string.
Set2 SETotherwiseMember count, then each member as a string.
Hash16 HASH_LISTPACKat most 512 fields, no field or value longer than 64 bytesA listpack of field, value, field, value.
Hash4 HASHotherwiseField count, then each field and value as strings.
Sorted set17 ZSET_LISTPACKat most 128 members, none longer than 64 bytesA listpack of member, score, member, score, in ascending score order.
Sorted set5 ZSET_2otherwiseMember count, then each member and its 8-byte score — walked from the skiplist tail, so highest score first (rdb.c:914–925).
Stream21 STREAM_LISTPACKS_3alwaysNot modelled here.

Thresholds are the shipped defaults from config.c:3236–3244. A list stays one listpack node until that node would exceed 8192 bytes, the limit list-max-listpack-size = -2 selects (quicklist.c:49, quicklist.c:467).

What this page leaves out

Functions (F5), module data (F7), streams, LZF compression, the LRU and LFU opcodes, and databases other than 0. The two hash-table branches (2 SET and 4 HASH) are written here in insertion order; a server writes them in dict iteration order, which is neither insertion order nor reproducible between runs. Everything else is the byte sequence Redis 7.2.14 would produce, including the CRC64, so redis-check-rdb accepts the download and a server loads it.