Key-Value Engine

Purpose-built hash-indexed store with O(1) point lookups, native TTL, and secondary indexes. Unlike a standalone KV store, data is SQL-queryable, joinable, and syncable via CRDTs.

When to Use

  • Session state and tokens
  • Feature flags and configuration
  • Rate limiters and counters
  • Caching without an external cache
  • Leaderboards and rankings

SQL Usage

CREATE COLLECTION sessions (key TEXT PRIMARY KEY) WITH (engine='kv');

-- Insert with TTL; plain INSERT raises unique_violation (23505) on duplicate key.
INSERT INTO sessions { key: 'sess_abc', user_id: 'alice', role: 'admin', ttl: 3600 };

-- Set-or-overwrite (Redis SET semantics)
UPSERT INTO sessions { key: 'sess_abc', user_id: 'alice', role: 'admin', ttl: 3600 };

-- Set-if-absent (Redis SETNX semantics)
INSERT INTO sessions { key: 'sess_abc', user_id: 'alice', role: 'admin', ttl: 3600 }
ON CONFLICT DO NOTHING;

-- Conditional merge: bump counter on conflict, EXCLUDED references the incoming row.
INSERT INTO sessions (key, user_id, role, hits) VALUES ('sess_abc', 'alice', 'admin', 1)
ON CONFLICT (key) DO UPDATE SET
  role = EXCLUDED.role,
  hits = sessions.hits + 1;

-- Get by key
SELECT * FROM sessions WHERE key = 'sess_abc';

-- Analytical queries work too
SELECT role, COUNT(*) FROM sessions GROUP BY role;

-- Join with other collections
SELECT u.name, s.role FROM users u JOIN sessions s ON u.id = s.user_id;

Atomic Operations

SELECT KV_INCR('counters', 'page_views', 1);
SELECT KV_DECR('credits', 'user-123', 50);
SELECT KV_CAS('state', 'player-1', 'idle', 'in_match');
SELECT KV_GETSET('token', 'sess-1', 'new-token');
SELECT KV_INCR('daily_logins', 'user-1', 1, TTL => 86400);

Sorted Indexes (Leaderboards)

CREATE SORTED INDEX lb_global ON scores (score DESC, updated_at ASC) KEY player_id;

SELECT RANK(lb_global, 'player-123');
SELECT * FROM TOPK(lb_global, 10);
SELECT * FROM RANGE(lb_global, 100, 250.5);
SELECT SORTED_COUNT(lb_global);

-- Time-windowed leaderboard
CREATE SORTED INDEX lb_daily ON scores (score DESC, updated_at ASC) KEY player_id
  WINDOW DAILY ON updated_at;

-- Fixed-range window: bounds are milliseconds or ISO 8601
CREATE SORTED INDEX lb_season ON scores (score DESC, updated_at ASC) KEY player_id
  WINDOW CUSTOM START '2026-01-01' END '2026-04-01' ON updated_at;

Sort Order

Each sort column orders its values by type first, then by value:

OrderTypeOrder within the type
1null—
2booleanfalse before true
3numbernumeric value
4stringbyte order of the UTF-8 text
5array or objectbyte order of the JSON text
  • Integers and floats share one numeric order. 10.5 sorts between 10 and 11.
  • The order is exact for every 64-bit integer and every float. Integers above 2^53 keep their order.
  • An integer and a float of equal value are equal. 11 and 11.0 hold one position.
  • -0.0 equals 0.
  • A non-finite float is stored as the text NaN, Infinity or -Infinity, so it sorts as a string.
  • RANGE(index, min, max) is inclusive at both ends and reads the first sort column. An integer bound matches a float row of equal value.
  • DESC reverses all of the above for that column.

Window Rules

  • The window timestamp column must be one of the sort columns. CREATE SORTED INDEX refuses the index otherwise (SQLSTATE 42601).
  • ON defaults to updated_at when the clause names no column.
  • DAILY, WEEKLY (from Monday) and MONTHLY windows start at 00:00 UTC of the current period.
  • A CUSTOM window is the half-open range [START, END). END must be after START.
  • A CUSTOM bound is integer milliseconds since the Unix epoch or an ISO 8601 date or instant.
  • A timestamp value is one of:
    • an integer: milliseconds since the Unix epoch;
    • a float: fractional milliseconds since the Unix epoch;
    • a string: an ISO 8601 date or instant.
  • Integers are milliseconds. A value in epoch seconds lands in January 1970 and falls outside current windows.
  • A row whose timestamp is null, a boolean, an array, an object, or a non-ISO 8601 string is hidden from every window.
  • A row without the timestamp field is not indexed.

Rate Gates

SELECT RATE_CHECK('attack_cooldown', 'player-123', 3, 10);
-- {"allowed": true, "remaining": 2, "resets_in_ms": 7500}

SELECT RATE_REMAINING('api_calls', 'tenant-1', 100, 60);
SELECT RATE_RESET('attack_cooldown', 'player-123');

Redis-Compatible Access (RESP)

Enable by setting ports.resp = 6381 in config. Any Redis client works:

redis-cli -p 6381
SET sess_abc '{"user":"alice"}' EX 3600
GET sess_abc
INCR page_views
ZADD leaderboard 1500 player-123
ZRANK leaderboard player-123

Supported: GET, SET, DEL, EXISTS, MGET, MSET, EXPIRE, TTL, SCAN, KEYS, HGET, HSET, INCR, DECR, ZADD, ZREM, ZRANK, ZRANGE, SUBSCRIBE, PUBLISH, and more.

View page sourceLast updated on Oct 18, 2026 by Farhan Syah