CapyDB/ docs
GuidesK/V

Clients

Connecting to a CapyDB K/V store over the Upstash REST protocol or RESP - @upstash/redis, @capydb/kv, ioredis, redis-py, go-redis and redis-cli.

A K/V store speaks two protocols. Both are standard, so migrating in is a URL and a token.

ProtocolEndpointUse it from
Upstash REST over HTTPSCAPYDB_KV_REST_URLServerless and edge runtimes, anything without a connection pool
RESP over TLSrediss://…:6379Long-lived servers, blocking commands, pub/sub

Upstash REST

The REST protocol carries pipelining, transactions and base64 encoding, so @upstash/redis works at its default settings - including Upstash-Encoding: base64 and auto-pipelining, both of which the client turns on for you.

import { Redis } from '@upstash/redis'

const redis = new Redis({
  url: process.env.CAPYDB_KV_REST_URL!,
  token: process.env.CAPYDB_KV_REST_TOKEN!,
})

await redis.set('user:1', { name: 'Ada' })
const user = await redis.get<{ name: string }>('user:1')

const [count, ttl] = await redis
  .pipeline()
  .incr('visits')
  .ttl('visits')
  .exec()

Redis.fromEnv() reads UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN. CapyDB publishes its own names, so either construct the client explicitly or set the UPSTASH_* names yourself.

Calling the endpoint directly, without a client:

curl "$CAPYDB_KV_REST_URL/set/greeting/hello" \
  -H "Authorization: Bearer $CAPYDB_KV_REST_TOKEN"

curl "$CAPYDB_KV_REST_URL" \
  -H "Authorization: Bearer $CAPYDB_KV_REST_TOKEN" \
  -d '["GET", "greeting"]'

@capydb/kv

@capydb/kv is a small factory that reads the CapyDB variable names and returns a configured @upstash/redis client. It exists so you do not hand-wire the same three lines in every service; it is not a wrapper, and the object it returns is an @upstash/redis client with nothing added.

npm install @capydb/kv @upstash/redis
import { createKv } from '@capydb/kv'

const kv = createKv()
await kv.set('hello', 'world')

It reads CAPYDB_KV_REST_URL / CAPYDB_KV_REST_TOKEN, falling back to UPSTASH_REDIS_REST_URL / UPSTASH_REDIS_REST_TOKEN so an existing Upstash deployment keeps working. It refuses a plaintext http:// URL unless you opt in explicitly.

RESP

Ordinary Redis® OSS clients connect over TLS on port 6379, with the token as the password. Blocking commands and pub/sub work here and not over REST.

CapyDB publishes two environment variables, CAPYDB_KV_REST_URL and CAPYDB_KV_REST_TOKEN. It does not publish a name for the RESP URL - the examples below read REDIS_URL, which is the ordinary convention, and you set it yourself from the value the create or rotate response returned.

ioredis
import Redis from 'ioredis'

const redis = new Redis(process.env.REDIS_URL!)
const job = await redis.blpop('queue', 0)
redis-py
import redis

r = redis.from_url(os.environ["REDIS_URL"])
r.set("hello", "world")
go-redis
opt, err := redis.ParseURL(os.Getenv("REDIS_URL"))
if err != nil {
    return err
}
client := redis.NewClient(opt)
redis-cli
redis-cli --tls -u "$REDIS_URL" PING

The RESP URL embeds the token as its password, so it only exists in full on the create and rotate responses. GET .../kv/credentials returns the endpoint without one and sets token_required: true; if you no longer have the token, rotate.

Commands that are not available

The store's ACL denies the administrative and replication surface. Everything a client application does is allowed; everything that would reconfigure the cell, take over its replication, or read another tenant's traffic is not:

CONFIG, SHUTDOWN, DEBUG, MODULE, REPLICAOF / SLAVEOF, SAVE / BGSAVE / BGREWRITEAOF, ACL, CLUSTER, MIGRATE, SYNC / PSYNC, MONITOR, FAILOVER, RESET.

Persistence and eviction are managed by CapyDB, which is why CONFIG and the SAVE family are not yours to call - see Operations.

Migrating from Upstash

Change two variables. The REST protocol, the client, the limiter and the command surface are the same; what changes is the region the store sits in and the fact that it is billed as part of your plan rather than per command.

If you already read UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN throughout your code, set those names to CapyDB's values and change nothing else.