Use ColibriDB from your code.

Every way to talk to a cluster: HTTP calls, Redis commands and the client libraries, with examples you can paste. The Connect page of your Admin console prints your cluster's exact addresses and credentials.

Connect

Applications talk to the proxies, which route every key to the node that owns it and follow failovers for you. Pick the surface that suits your stack; they all see the same data.

EndpointDefault portUse it forAuthentication
HTTP proxy5006curl, any language, the Python and TypeScript clientsBearer token, Basic, JWT (OIDC) or an ACL user
Binary proxy6400The .NET client: the lowest latencyAPI key or an ACL user
RESP on the nodes6379redis-cli and any Redis client (StackExchange.Redis, redis-py, ioredis, go-redis)AUTH with the cluster key or an ACL user
The examples below use two variables
# From Admin → Connect: the HTTP proxy address and a token
export COLIBRI_URL=https://db.example.com:5006
export COLIBRI_TOKEN=your-proxy-token

Keys over HTTP

The value is the raw request body, any bytes up to the configured limit. The key is one path segment: write a / inside a key as %2F.

curl
# Write a value that expires in one hour
curl -X PUT "$COLIBRI_URL/kv/user:42?ttlSeconds=3600" \
  -H "Authorization: Bearer $COLIBRI_TOKEN" \
  --data-binary '{"name":"Ada","plan":"pro"}'

# Read it back (404 when the key does not exist)
curl "$COLIBRI_URL/kv/user:42" -H "Authorization: Bearer $COLIBRI_TOKEN"

# Write only if the key is absent: a simple lock (409 if someone holds it)
curl -X PUT "$COLIBRI_URL/kv/lock:report?nx=true&ttlSeconds=30" \
  -H "Authorization: Bearer $COLIBRI_TOKEN" --data-binary "worker-7"

# List keys by prefix, 100 at a time (values come base64; pass nextCursor to continue)
curl "$COLIBRI_URL/kv?prefix=user:&limit=100" -H "Authorization: Bearer $COLIBRI_TOKEN"

# Delete it
curl -X DELETE "$COLIBRI_URL/kv/user:42" -H "Authorization: Bearer $COLIBRI_TOKEN"
CallWhat it doesAnswers
GET /kv/{key}Reads the value200 with the bytes · 404
PUT /kv/{key}Writes the value. ?ttlSeconds=N expires it, ?nx=true writes only if absent, ?xx=true only if present204 · 409 (nx) · 404 (xx) · 413 too large
DELETE /kv/{key}Deletes the key204 · 404
GET /kv?prefix=&limit=&cursor=Scans keys in pages{ items:[{key, value}], nextCursor }
GET /healthLiveness and role, no credentials needed200

Hashes, sets, sorted sets and lists

The same atomic operations as the Redis commands, with JSON bodies (Content-Type: application/json). Strings travel as text; add ?encoding=base64 to send and receive binary values.

curl
# A hash: set fields, increment one, read them all
curl -X PUT "$COLIBRI_URL/hash/cart:7" -H "Authorization: Bearer $COLIBRI_TOKEN" \
  -H "Content-Type: application/json" -d '{"fields":{"sku-1":"2","sku-9":"1"}}'
curl -X POST "$COLIBRI_URL/hash/cart:7/incr" -H "Authorization: Bearer $COLIBRI_TOKEN" \
  -H "Content-Type: application/json" -d '{"field":"sku-1","by":3}'
curl "$COLIBRI_URL/hash/cart:7" -H "Authorization: Bearer $COLIBRI_TOKEN"
# → {"key":"cart:7","count":2,"fields":{"sku-1":"5","sku-9":"1"}}

# A sorted set: add scores, read the top 10
curl -X PUT "$COLIBRI_URL/zset/leaderboard" -H "Authorization: Bearer $COLIBRI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"members":[{"member":"ada","score":120},{"member":"bob","score":95}]}'
curl "$COLIBRI_URL/zset/leaderboard?start=0&stop=9&rev=true" -H "Authorization: Bearer $COLIBRI_TOKEN"

# A list as a queue: push at the end, pop from the front
curl -X POST "$COLIBRI_URL/list/jobs/push" -H "Authorization: Bearer $COLIBRI_TOKEN" \
  -H "Content-Type: application/json" -d '{"side":"right","values":["job-1","job-2"]}'
curl -X POST "$COLIBRI_URL/list/jobs/pop" -H "Authorization: Bearer $COLIBRI_TOKEN" \
  -H "Content-Type: application/json" -d '{"side":"left","count":1}'

# A set: add members, test one
curl -X PUT "$COLIBRI_URL/set/tags:42" -H "Authorization: Bearer $COLIBRI_TOKEN" \
  -H "Content-Type: application/json" -d '{"members":["vip","beta"]}'
curl "$COLIBRI_URL/set/tags:42?member=vip" -H "Authorization: Bearer $COLIBRI_TOKEN"
TypeCallsLike
/hash/{key}GET (?field=…), PUT { fields }, DELETE ?field=…, POST /incr { field, by }HGETALL, HSET, HDEL, HINCRBY
/set/{key}GET (?member=…), PUT { members }, DELETE ?member=…, POST /pop { count }SMEMBERS, SADD, SREM, SPOP
/zset/{key}GET ?start&stop&rev or ?min&max, PUT { members:[{member, score}] }, POST /incr, POST /popZRANGE, ZADD, ZINCRBY, ZPOPMIN
/list/{key}GET ?start&stop, POST /push { side, values }, POST /pop { side, count }, POST /trimLRANGE, LPUSH/RPUSH, LPOP/RPOP, LTRIM

Redis commands

Turn on RESP for the nodes (Admin → Configuration) and use redis-cli or the Redis client you already have. With TLS on, connect with --tls or a rediss:// URL.

redis-cli
redis-cli -h db.example.com -p 6379 --tls -a "$COLIBRI_PASSWORD"

SET user:42 '{"name":"Ada"}' EX 3600
GET user:42
HSET cart:7 sku-1 2 sku-9 1
ZADD leaderboard 120 ada 95 bob
ZREVRANGE leaderboard 0 9 WITHSCORES
MULTI
INCR visits:today
EXPIRE visits:today 86400
EXEC

Compatibility is verified by a test suite and by client checks with StackExchange.Redis, redis-py and ioredis, over RESP2 and RESP3:

AreaStatusNotes
Connection, AUTH, PING, HELLO 2 and 3, pipelining Supported Writes in one pipeline share a group commit; see Pipelined writes below
Strings, TTL, SET options, INCR, APPEND, GETRANGE and SETRANGE Supported Expiry is lazy plus a periodic sweep
Keys: KEYS, SCAN, RENAME, COPY and TOUCH Supported Multi-key commands need keys in one shard; use a {hash tag}
Hashes Supported Whole collection rewritten per write, 4 MiB cap
Sets, sorted sets and lists Partial Unions, intersections, STORE variants, LMOVE and lex ranges included; no blocking operations yet
Bitmaps Supported SETBIT, GETBIT, BITCOUNT, BITPOS and BITOP; no BITFIELD
MULTI, EXEC and WATCH Partial Keys must live in one shard; use {hash tags}. EXEC is atomic and crash-safe
Pub/sub Supported Cluster-wide when the relay is configured, otherwise node-local
Keyspace notifications Supported Events for writes from every protocol
RESP3 Supported Maps, sets, doubles and push frames after HELLO 3
Client-side caching (CLIENT TRACKING) Not supported
Streams, Lua and EVAL, HyperLogLog, geo Not supported
FLUSHDB, FLUSHALL, SELECT above 0, CLUSTER Not supported Refused

Client libraries

The client packages come with your license. They follow leader changes, retry reads safely and never repeat a write that may already have been applied.

binary protocol
using ColibriDB.Client;

await using var db = new ColibriClient(new ColibriClientOptions
{
    Host = "db.example.com",
    Port = 6400,
    ApiKey = Environment.GetEnvironmentVariable("COLIBRI_KEY"),
});

await db.PutAsync("user:42", "{\"name\":\"Ada\"}");
string? user = await db.GetStringAsync("user:42");
var many = await db.GetManyAsync(["user:1", "user:2", "user:3"]);
HTTP API, standard library only
import os
from colibridb import ColibriClient

with ColibriClient(os.environ["COLIBRI_URL"], bearer=os.environ["COLIBRI_TOKEN"]) as db:
    db.put("user:42", '{"name":"Ada"}', ttl_seconds=3600)
    db.get_text("user:42")                      # '{"name":"Ada"}'
    db.put("lock:report", "worker-7", nx=True)  # False if the key exists
    db.hash_set("cart:7", {"sku-1": "2"})
    db.zset_add("leaderboard", {"ada": 120, "bob": 95})
    for key, value in db.iter_scan("user:"):
        print(key, value)
HTTP API, no dependencies
import { ColibriClient } from "@colibridb/client";

const db = new ColibriClient({
  baseUrl: process.env.COLIBRI_URL!,
  bearer: process.env.COLIBRI_TOKEN!,
});

await db.put("user:42", JSON.stringify({ name: "Ada" }), { ttlSeconds: 3600 });
const user = await db.getText("user:42");
await db.put("lock:report", "worker-7", { nx: true }); // false if the key exists
await db.zsetAdd("leaderboard", new Map([["ada", 120], ["bob", 95]]));
for await (const [key, value] of db.iterScan("user:")) {
  console.log(key, value);
}
ClientProtocolGET on loopbackNotes
.NETBinary, port 6400about 37 µsPooled, pipelined connections; TLS and mTLS. No TTL or scan on this protocol: use HTTP for those
PythonHTTP, port 5006about 75 µsPython 3.9+, one keep-alive connection per thread; hashes, sets, sorted sets, lists and vectors
TypeScriptHTTP, port 5006about 65 µsNode, Deno, Bun and browsers; the same typed methods as Python

Errors and retries

Errors come as Problem Details JSON (type, title, detail). The clients handle redirects and safe retries for you; with plain HTTP, this is what each status means and what to do.

StatusMeaningWhat to do
401 · 403Missing or wrong credentials, or the ACL denies this keyCheck the token or the user's key patterns
404The key does not exist (or xx=true found nothing)Treat as a miss
409nx=true found the key, or the key holds another typeRead the key, or use another name
413Value or collection over the size limitSplit the value; nothing was written
421The node is not the leader of this key's groupRepeat at X-Colibri-Leader-Url; nothing was applied
429The ACL user's rate limitBack off and retry
503Election, migration or no quorum (Retry-After)Retry reads; retry writes only with X-Colibri-Fenced: raft-not-applied
504The write's outcome is unknownRead the key before repeating the write
507The tenant's quota is fullReads and deletes still work; free space or raise the quota

Pipelined writes and durability

A client that sends writes back to back on one connection gets them committed together, and the replies stay in request order. These are the settings and what they guarantee.

SettingDefaultRangeNotes
Node__PipelinedWrites 128 0 to 4096 Plain SET and PUT writes in flight per connection, on RESP and the binary protocol. 0 turns it off.
Node__PipelinedWriteBytes 1 MiB 1 B to 256 MiB Key and value bytes in flight per connection. A single larger write is not deferred.
ProxyBinary__PipelinedFrames 128 0 to 1024 GET, PUT and DELETE frames the binary proxy forwards to a node before reading replies. 0 or 1 turns it off.
ProxyBinary__PipelinedBytes 1 MiB 0 to 1 GiB Request bytes in one forwarded batch. 0 turns it off.
ProxyBinary__PipelinedResponseBytes 2 MiB 64 KiB to 1 GiB Replies a batch may hold out of order. Over it, the proxy stops reading that node connection until its turn.
ProxyBinary__MaxIdleBackendConnectionsPerNode 1024 0 to 10000 Idle connections kept open per node. Keep it at or above the real number of concurrent clients.
ProxyBinary__BackendIdleTimeoutSeconds 240 1 to 299 Idle seconds after which a connection to a node is closed. It stays below the node's 300 s idle timeout.
  • Any other command, a repeated key or a protocol error ends the run first, so a command that follows a write in the same pipeline sees it.
  • With WalPolicy Always, a run costs one fsync instead of one per write. Raft groups always use Always.
  • With WalPolicy Interval, the periodic fsync runs in a background task and writes do not wait for it. The loss window is still at most WalFlushIntervalMs.
  • If the fsync of the file replication log fails, the shard keeps serving and replication degrades: node health reports Degraded, the metric colibri.engine.replication_faulted_shards counts the shard and a .gap marker stays beside the log. Replay refuses a log with a hole, so the replica must be resynced.
  • The log API, replication and the vector index never see a log position before its data is readable. If applying a write to the index fails after the commit, the shard stops instead of answering with a misleading error.
  • A failed fsync while a segment rotates is never reported as durable.

Architecture, security, operations and the full configuration reference come with your license. Ask us for them