Reference

Redis compatibility

Nexir speaks RESP2 and exposes a deliberately small, scalar-only Redis-compatible command surface. It is not a Redis replacement.

Connect

redis-cli --raw -h 127.0.0.1 -p 6379
PING
# PONG
HELLO
# includes server nexir, proto 2, mode cluster

Configure client libraries for RESP2. HELLO does not negotiate RESP3, authentication, or RESP3 reply shapes.

Supported commands

This table is the complete surface. Every command not listed here returns ERR unknown command '<name>'. Command names are case-insensitive; keys and values are binary-safe.

CommandResultSemantics
GET keybulk value or nilReads one live scalar value.
SET key valueOKUnconditionally replaces the value and clears its deadline.
SET key value EX secondsOKReplaces the value with a relative seconds deadline.
SET key value PX millisecondsOKReplaces the value with a relative millisecond deadline.
SET key value EXAT unix-secondsOKReplaces the value with an absolute seconds deadline.
SET key value PXAT unix-millisecondsOKReplaces the value with an absolute millisecond deadline.
DEL key0 or 1Deletes exactly one key. Variadic DEL is not supported.
EXPIRE key seconds0 or 1Sets a relative seconds deadline.
PEXPIRE key milliseconds0 or 1Sets a relative millisecond deadline.
EXPIREAT key unix-seconds0 or 1Sets an absolute seconds deadline.
PEXPIREAT key unix-milliseconds0 or 1Sets an absolute millisecond deadline.
PERSIST key0 or 1Clears an existing deadline.
TTL keyinteger seconds-2 when absent, -1 when persistent.
PTTL keyinteger milliseconds-2 when absent, -1 when persistent.
Operational commandPurpose
HELLO [2 [SETNAME name]]RESP2 negotiation and server identity.
PING [message]Connection liveness.
ECHO messageConnection diagnostics.
QUITClean connection shutdown.
SELECT 0Accepts clients that explicitly select database zero. Any other index errors.
COMMAND [subcommand]Metadata generated from the authoritative command registry.
CONFIG GET parameterRead-only client-initialization compatibility for persistence probes.
CLIENT READMODE LOCAL|LINEARIZABLEChooses local or linearizable reads for the connection.
INIT id grpc redisInitializes a fresh local Raft cluster when RESP administration is enabled.
CLUSTER ...Membership, leadership, health, and readiness administration.

INIT and mutating CLUSTER subcommands are gated by server.enable_admin_commands, which is disabled by default. Enable it explicitly during bootstrap or membership changes, require client mTLS on the RESP listener on any network that is not strictly isolated, and disable it again when the operation is complete. Nexir has no AUTH command; the certificate is the only client authentication. See the CLI and network reference for the full CLUSTER subcommand list.

COMMAND metadata

FormResult
COMMANDFull detail array for every registered command.
COMMAND COUNTNumber of registered commands.
COMMAND INFO [name ...]Detail entry per name; unknown names are null arrays.
COMMAND DOCS [name ...]Empty map; structured documentation is not exposed yet.
COMMAND LISTNames of all registered commands.

Subcommands are case-insensitive. COMMAND GETKEYS, COMMAND HELP, and structured COMMAND DOCS output are not supported.

HELLO protocol negotiation

Nexir speaks RESP2 only. Bare HELLO and HELLO 2 return the RESP2 server-identity map. HELLO 2 SETNAME name is accepted for client compatibility, but the name is not retained.

HELLO 3, and every other unsupported numeric protocol version, returns:

-NOPROTO unsupported protocol version

This deliberately differs from Redis, which negotiates RESP3. Explicit rejection prevents a client from switching to RESP3 while Nexir continues emitting RESP2 frames. A non-integer or out-of-range version returns -ERR Protocol version is not an integer or out of range. AUTH inside HELLO returns -ERR AUTH is not supported, because Nexir will not report an authentication it did not perform. Unknown or incomplete modifiers return -ERR Syntax error in HELLO. These command errors leave the connection open.

CONFIG GET

CONFIG GET save returns an empty value and CONFIG GET appendonly returns no, which is enough for client libraries that probe persistence during initialization. CONFIG GET * returns both. Any other parameter returns an empty array. CONFIG SET is not supported; change TOML or environment variables and restart the node.

TTL behavior

  • TTL and PTTL return -2 for missing or expired keys, -1 for a key with no deadline.
  • Relative deadlines are converted to absolute Unix milliseconds by the leader before proposal. Replicas apply the captured deadline and never re-derive it from their own wall clocks.
  • A deadline at or before the captured command time deletes an existing key.
  • Expired records are logically absent at the exact deadline, before background physical cleanup completes.
  • Expiration cleanup carries the expected deadline, so a later overwrite cannot be deleted by an earlier cleanup request.
  • SET without a deadline option clears an existing deadline.
  • Only the four documented SET deadline options are valid. Invalid arity, syntax, integers, bounds, and request limits fail before Raft proposal and cannot partially change state.

Consistency and routing

Writes always require Raft quorum. A follower redirects writes with MOVED when it knows the leader.

CLIENT READMODE LINEARIZABLE
# OK — default; requires a Raft read barrier

CLIENT READMODE LOCAL
# OK — served by the contacted node; followers may be stale

Linearizable reads may redirect from followers or fail during quorum loss. Local reads never redirect but can observe older state. READMODE is the only CLIENT subcommand; there is no write-mode selector, because every write is a quorum write.

Pipelining and command ordering

Nexir returns exactly one reply per request, in request order. Replies are never reordered, merged, or omitted. Execution order within a single connection's pipeline is guaranteed only in these directions:

Pipelined pair, same connectionGuaranteed
write then writeYes. Writes are proposed in submission order and Raft preserves it.
write then readYes. A read queued behind an uncommitted write on the same connection waits for it, so pipelined read-your-writes holds.
read then writeNo. The read may observe the later write's effect.
read then readNo. Two reads in one pipeline may be evaluated against snapshots taken in either order.

Concretely: GET k pipelined immediately before SET k v may return v, and GET k pipelined before DEL k may return nil. This is not a linearizability violation — pipelined commands are issued before any of their replies is received, so they are concurrent operations and any serialization of them is valid. It is a deliberate deviation from Redis, which executes one connection's commands strictly in submission order. The window is wider under LINEARIZABLE than LOCAL, because a linearizable read waits for a Raft read barrier before taking its snapshot.

A client that needs submission order across a read-then-write boundary must read the reply to the read before issuing the write. Sequential request/response clients are unaffected, and no ordering was ever guaranteed between commands on different connections.

RESP multibulk compatibility

Empty (*0) and null or negative (*-1, *-2, and so on) multibulk frames are consumed without producing a reply. The connection stays open and continues with the next frame, matching Redis.

Limits

  • Command name: 512 bytes. Keys: 1 MiB.
  • Values and aggregate request size: 60 MiB.
  • Request multibulk: 128 arguments while the surface is scalar-only. Wider frames are rejected from the array header before payload parsing. The 25,000-element RESP array ceiling remains the outer bound; this tighter limit will be revisited with the multi-key and sharding design.
  • Replies are bounded by storage.max_read_reply_bytes and the client and global response budgets.

Unsupported features

Hashes, sets, lists, sorted sets, counters (INCR and friends), multi-key commands (MSET, MGET), EXISTS, TYPE, STRLEN, APPEND, DBSIZE, KEYS, cursor SCAN, FLUSHDB/FLUSHALL, Lua and functions, MULTI/EXEC/WATCH, streams, pub/sub, blocking operations, modules, geospatial commands, HyperLogLog, persistence commands, AUTH, and every other Redis command outside the tables above are unsupported and return ERR unknown command.

Because there is exactly one value type, Nexir never returns WRONGTYPE.

Common errors

  • ERR unknown command '<name>' for any command outside the surface.
  • MOVED when a request should reach the leader.
  • CLUSTERDOWN when leadership or quorum is unavailable.
  • NOPROTO for an unsupported HELLO protocol version.
  • ERR Server overloaded or queue/buffer errors when configured bounds are reached.
  • Explicit size errors for oversized command names, keys, values, requests, or replies.