Memory Calculator for Redis and Valkey

Describe your keys, how many there are, how long their names are and what they hold, and see how much memory Redis or Valkey needs for them: how much used_memory grows, version by version. The calculator names the encoding each kind of value gets, shows the hash tables behind the keys and their expiry times, says which limit to raise when values are stored in their big form, and works out what packing small strings into hashes would save. It all runs in your browser.

Nothing you type leaves this page. The tool doesn’t send anything anywhere, and the page’s security policy stops it from fetching or loading anything from another site, so your data stays on your machine.

On a wide screen you can open it full screen.

How to Use It

  1. Describe your keys. For each kind of key: the type, how many, how long the names are (or type an example name and the calculator counts its bytes), and what they hold. A value is text of some length, or a number, which the server can store as one. Hash fields and set members can be numbers that count up from the one you give. Say what share of the keys has a TTL, and whether collections are written in one command or one element at a time.
  2. Pick the server. The figures change as you type. Open Server settings if your servers don’t use the default limits.
  3. Read the result. The growth of used_memory, how each kind of value is stored and what it costs a key, and the hash tables behind the keys. A warning shows up when values are past a limit, with what raising it would save.
  4. Compare and plan. The same keys on all 15 versions, string keys packed into hashes, and the RAM to plan for once fragmentation and snapshots are counted.

As text shows the keys in the form the command line takes, ready to copy.

Where the Memory Goes

Every byte the server uses is a block it asked the allocator for. Redis and Valkey are built with jemalloc, which hands out blocks in fixed sizes: 8, 16, 24 and so on up to 64 bytes, then four sizes in each doubling, 80, 96, 112, 128, 160 and up. A request for 65 bytes gets 80. used_memory adds up those blocks, so the calculator counts in the same sizes.

A key costs something before its value does. Up to Redis 8.0 and Valkey 7.2, a key is a 24-byte entry in the keyspace’s hash table, a copy of its name and a 16-byte object that points at the value. Valkey 8.0 keeps the name inside that entry. Redis 8.2 and Valkey 8.1 put the name inside the object, and a short string value with it, in one block. A key of 11 bytes with a value of 10 takes 72 bytes on Redis 7.2 and 48 on Redis 8.10.

The keyspace is a hash table. Its array of buckets doubles as it fills: one 8-byte slot per key, rounded up to a power of two, so 8 to 16 bytes a key. Valkey 8.1 and later use 64-byte buckets of seven keys each. A key with a TTL is in a second table too. When two keys land in the same bucket, Redis 8.2 and later need a 16-byte entry for the second, and a Valkey bucket that gets an eighth key needs a 64-byte overflow bucket. Chance decides how many, so the calculator gives the expected number and how far it can stray.

Small values are packed. A small hash, set, sorted set or list is one compact block, a listpack (a ziplist in Redis 6.2), and a set of numbers is an intset. Past a limit, the value turns into a hash table or a skiplist, where every field or member becomes blocks of its own. On Redis 8.10, a hash under a 16-byte key with 512 fields of 8 bytes and 10-byte values takes 12,328 bytes, its key included. With 513 fields it takes about 22,357. The limits are settings: hash-max-listpack-entries is 512 and hash-max-listpack-value 64 bytes, and sets and sorted sets have their own.

Numbers are cheap. A number such as 1759734012 is kept as an integer: 6 bytes in a listpack instead of 12 for the text, or inside the key’s object instead of a string of its own. Up to Redis 8.0 and Valkey 8.0, the numbers 0 to 9999 as string values cost nothing beyond their key, since every key shares the same objects, unless maxmemory is set with an LRU or LFU maxmemory-policy.

Small Strings Packed Into Hashes

Ten million small strings each pay for a key, an object and a slot in the keyspace. Kept as fields of hashes, a hundred to a hash, they share keys: user:1234567 becomes field 67 of the hash user:12345. The hashes stay listpacks while they have no more than hash-max-listpack-entries fields, and the fields, being numbers, take 2 or 3 bytes each. On Redis 8.10, ten million keys of 13 bytes with 8-byte values take 623 MB as strings and 127 MB as 100,000 hashes. The price: a hash has one TTL for all its fields, and every read names both the hash and the field.

What Changed Between Versions

The same keys can take a third less on one version than on another: ten million keys of 13 bytes with 8-byte values need 85 bytes a key on Redis 7.2 and 55 on Valkey 9.1. Redis 7.2 keeps small sets of strings in listpacks; before, any set that wasn’t all numbers was a hash table. Valkey 8.0 put the key inside the keyspace’s own entry. Redis 8.2 and Valkey 8.1 moved it into the value’s object instead, and Valkey 8.1 replaced its hash tables with a design of its own. Redis 8.6 and Valkey 8.1 keep a hash field and its value in one block, and Redis 8.6 and Valkey 9.1 keep a sorted set’s members inside its skiplist nodes. Valkey 9.1 fits string values of up to about 100 bytes into the key’s object.

Not every change helps every shape. A million keys of 20 bytes with 30-byte values take 82 MB on Redis 8.10 and 107 MB on Redis 7.2. Valkey 9.1 puts that value inside the key’s object, a block of 65 bytes, one past a size class, so it takes 80; Valkey 8.1 keeps them apart in blocks of 40 and 32, and needs 85 MB where 9.1 needs 93.

How It Was Tested

All 15 versions were built from source with their own jemalloc: Redis 6.2.24, 7.0.15, 7.2.16, 7.4.11, 8.0.6, 8.2.10, 8.4.7, 8.6.7, 8.8.3 and 8.10.2, and Valkey 7.2.14, 8.0.11, 8.1.10, 9.0.6 and 9.1.2. A script wrote keys of more than 6,200 shapes to each one and read used_memory before and after: strings of every length around the points where the encoding changes, with and without TTLs, numbers, values of 32 KB to 1 MB, up to 30,000 keys at once around the sizes where the tables double, hashes, sets, sorted sets and lists below and above every limit, written in one command or one element at a time, sorted set scores of every kind, mixes of all of them, and other settings.

  • To the byte. Told what chance decided, how many keys shared a bucket and how many overflow buckets the tables needed, the calculator gives the same growth as the server for every one of the 94,061 cases, apart from the skiplists of big sorted sets.
  • Skiplists. Each node of a skiplist gets a random number of levels, which nobody can see from outside. Those cases agree within a few standard deviations, and on average to within a small fraction of one. A sorted set of one member takes exactly what one node at some level takes.
  • Chance. Without knowing what chance decided, the expected values land within three standard deviations in 99.8% of the cases, scattered evenly around the measurement.

The servers ran with their default settings, apart from the cases that change them. The calculator gives the memory for keys written by clients; a server that loaded its data from a snapshot at startup sizes some tables at once and can differ by a few percent.

The Code

The calculator’s logic is one JavaScript file with no dependencies, open source under the Apache License 2.0. It runs as this page, as a command line in Node.js, and inside your own code:

node memory/cli.js "1m strings key=24 value=100 ttl=30%" --server valkey-9.1
node memory/cli.js "50000 hashes key=16 fields=600 field=8 value=20" --compare
node memory/cli.js "10m strings key=13 value=8" --pack 100

The full manual, the tests and the measurements they replay are in the memory folder on GitHub. The other tools work the same way.