Bitmaps
Bitmaps are not a separate type: they are strings read and written one bit at a time. Bit offset 0 is the most significant bit of the first byte. Because each flag costs a single bit, a bitmap can record a yes/no fact for millions of numeric IDs in a few megabytes, and the server can count or combine them quickly. Typical uses are “which users were active today”, feature flags per user ID, and presence grids.
BITFIELD goes one step further and packs small integers (for example many 8-bit counters) into one string.
Create, read, update, delete
Section titled “Create, read, update, delete”SETBIT sets or clears one bit and replies with its previous value. A missing key is created, and the string grows (padded with zero bits) to reach the offset. GETBIT reads a bit; bits past the end of the string read as 0.
127.0.0.1:6379> SETBIT logins:2026-10-01 3 1(integer) 0127.0.0.1:6379> SETBIT logins:2026-10-01 7 1(integer) 0127.0.0.1:6379> SETBIT logins:2026-10-02 3 1(integer) 0127.0.0.1:6379> SETBIT logins:2026-10-02 5 1(integer) 0127.0.0.1:6379> GETBIT logins:2026-10-02 5(integer) 1127.0.0.1:6379> GETBIT logins:2026-10-02 100(integer) 0127.0.0.1:6379> BITCOUNT logins:2026-10-01(integer) 2127.0.0.1:6379> BITPOS logins:2026-10-02 1(integer) 3Here the offset is a user ID: user 3 logged in on both days, user 7 only on the first, user 5 only on the second.
- BITCOUNT counts set bits, optionally in a range.
The range is in bytes by default; add
BITto give it in bits. - BITPOS finds the first bit set to 1 (or 0), optionally within a range.
- Since a bitmap is a string, GET returns the raw bytes and DEL removes it.
Combining bitmaps
Section titled “Combining bitmaps”BITOP computes AND, OR, XOR, NOT, DIFF, DIFF1,
ANDOR or ONE across bitmaps and stores the result. It replies with the length of the result in
bytes.
127.0.0.1:6379> BITOP AND logins:both logins:2026-10-01 logins:2026-10-02(integer) 1127.0.0.1:6379> BITCOUNT logins:both(integer) 1127.0.0.1:6379> BITOP OR logins:either logins:2026-10-01 logins:2026-10-02(integer) 1127.0.0.1:6379> BITCOUNT logins:either(integer) 3NOT takes exactly one source key. Shorter inputs are treated as if padded
with zero bytes.
Packed integers with BITFIELD
Section titled “Packed integers with BITFIELD”BITFIELD reads and writes integers of any width from 1 to 64 bits (signed
i<n>, or unsigned u<n> up to 63 bits) at any bit offset, several in one
call. OVERFLOW chooses what INCRBY does past the type’s range: WRAP
(the default), SAT to stick at the minimum or maximum, or FAIL to leave
the value and return nil.
127.0.0.1:6379> BITFIELD player:42 SET u8 0 2001) (integer) 0127.0.0.1:6379> BITFIELD player:42 INCRBY u8 0 1001) (integer) 44127.0.0.1:6379> BITFIELD player:42 OVERFLOW SAT INCRBY u8 0 2501) (integer) 255127.0.0.1:6379> BITFIELD player:42 GET u8 0 GET u8 81) (integer) 2552) (integer) 0BITFIELD_RO accepts only GET, so it can run on
read-only replicas.
Common patterns
Section titled “Common patterns”Daily active users. SETBIT active:<date> <user-id> 1 on each visit.
BITCOUNT gives the day’s count, BITOP AND across a week gives users
active every day, BITOP OR users active on any day.
Per-user feature flags. One bitmap per feature, offset = user ID.
GETBIT feature:new-checkout 42 is a constant-time check.
Many small counters. With BITFIELD, a single key can hold thousands of
fixed-width counters, addressed by offset, with saturating increments.
Limits and memory
Section titled “Limits and memory”A bitmap is as large as its highest set bit requires: setting bit 1,000,000 makes a string of about 122 KB even if no other bit is set. This makes bitmaps a great fit for dense numeric IDs and a poor one for sparse or very large IDs; for those, use a set, or a HyperLogLog if an approximate count is enough.
The highest usable bit offset follows proto-max-bulk-len: with the
default 512 MB, offsets go up to 2^32 - 1. Larger offsets are refused with
ERR bit offset is not an integer or out of range.
Expiry
Section titled “Expiry”A bitmap expires as a whole, like any string. Name keys by period
(active:2026-10-02) and give each an expiry, so old periods clean
themselves up.
Compatibility
Section titled “Compatibility”Bitmap commands follow Redis 8.2, including the DIFF, DIFF1, ANDOR and
ONE operations of BITOP.
Commands
Section titled “Commands”| Command | What it does |
|---|---|
| SETBIT | Set or clear a bit |
| GETBIT | Read a bit |
| BITCOUNT | Count set bits |
| BITPOS | Find the first 0 or 1 bit |
| BITOP | Combine bitmaps |
| BITFIELD | Read and write packed integers |
| BITFIELD_RO | Read-only BITFIELD |
From your application
Section titled “From your application”import hotkv
client = hotkv.HotKV(host="localhost", port=6379, decode_responses=True)
client.setbit("logins:2026-10-02", 3, 1)client.setbit("logins:2026-10-02", 5, 1)print(client.getbit("logins:2026-10-02", 5)) # 1print(client.bitcount("logins:2026-10-02")) # 2client.close()import { HotKV } from "@hotkv/client";
const client = new HotKV({ url: "hotkv://127.0.0.1:6379" });
await client.setBit("logins:2026-10-02", 3, 1);await client.setBit("logins:2026-10-02", 5, 1);console.log(await client.getBit("logins:2026-10-02", 5));console.log(await client.bitCount("logins:2026-10-02"));await client.close();client, err := hotkv.NewClient(&hotkv.Options{Addr: "localhost:6379"})if err != nil { log.Fatal(err)}defer client.Close()ctx := context.Background()
client.SetBit(ctx, "logins:2026-10-02", 3, 1)client.SetBit(ctx, "logins:2026-10-02", 5, 1)bit, _ := client.GetBit(ctx, "logins:2026-10-02", 5).Result()count, _ := client.BitCount(ctx, "logins:2026-10-02", nil).Result()fmt.Println(bit, count)import com.hotkv.HotKV;
try (HotKV client = HotKV.create("hotkv://localhost:6379")) { client.setBit("logins:2026-10-02", 3, 1); client.setBit("logins:2026-10-02", 5, 1); System.out.println(client.getBit("logins:2026-10-02", 5)); System.out.println(client.bitCount("logins:2026-10-02"));}Was this page helpful?
Thanks for the feedback.