Change your application: migrate from Upstash to KiviDB
There are two ways, and you can mix them: functions on the edge keep REST, long-running servers move to a Redis client.
There are two ways, and you can mix them: functions on the edge keep REST, long-running servers move to a Redis client.
Option A: keep @upstash/redis and use KiviDB's REST API
KiviDB Cloud's REST API speaks the same wire format as Upstash's. Turn it on under Configuration → REST API, then change the two variables your app reads and redeploy:
# Before
UPSTASH_REDIS_REST_URL="https://my-db-12345.upstash.io"
UPSTASH_REDIS_REST_TOKEN="AX..."
# After
UPSTASH_REDIS_REST_URL="https://your-name.cloud.kividb.io"
UPSTASH_REDIS_REST_TOKEN="kvr_..."
The code stays as it is:
import { Redis } from "@upstash/redis";
const redis = Redis.fromEnv();
await redis.set("user:1", { name: "Ada" }, { ex: 3600 });
const user = await redis.get("user:1");
The token is a database user's: kvr_ followed by username:password in
base64url. The console shows it beside each user in Configuration → Users
once the REST API is ready. A user with the Read only profile gives a
read-only token, like Upstash's.
What differs from Upstash's REST API:
- The REST API is on Essentials and Pro databases, not free or sharded ones.
- A request can be 10 MB, a reply 64 MB, a pipeline or transaction 1,000 commands, and a request 10 seconds.
SELECT,SUBSCRIBE,MULTI/EXECas separate requests,CLIENT,HELLO,AUTH, and blocking commands are refused, as on Upstash; useredis.multi()orredis.pipeline()for transactions and pipelines.- The port 443 endpoint follows the database's network rules: an address that can't reach the data ports can't reach it either. Functions on the edge come from many addresses, so check Configuration → Network allows them.
The REST API reference has the details.
Option B: move to a Redis client
For a server that runs continuously, a TCP client is faster than HTTP and
supports blocking commands and pub/sub. One thing needs care: @upstash/redis
stores objects and numbers as JSON text and parses them back on read. A
regular client returns the stored text, so parse it where your code stored
objects.
Node.js: @upstash/redis to ioredis
// Before
import { Redis } from "@upstash/redis";
const redis = Redis.fromEnv();
await redis.set("user:1", { name: "Ada", tags: ["a", "b"] }, { ex: 3600 });
const user = await redis.get("user:1"); // { name: "Ada", tags: [...] }
await redis.hset("profile:1", { name: "Ada", age: 36 });
const profile = await redis.hgetall("profile:1"); // { name: "Ada", age: 36 }
const p = redis.pipeline();
p.incr("visits");
p.expire("visits", 86400);
await p.exec();
// After
import fs from "node:fs";
import Redis from "ioredis";
const redis = new Redis({
host: "your-name.cloud.kividb.io",
port: 6380,
username: "kividbapp",
password: process.env.KIVIDB_PASSWORD,
tls: { ca: fs.readFileSync("kividb-ca.pem") },
});
// Values written by @upstash/redis are JSON text. Parse what parses,
// and leave plain strings as they are.
function fromUpstash(value: string | null) {
if (value === null) return null;
try {
return JSON.parse(value);
} catch {
return value;
}
}
await redis.set("user:1", JSON.stringify({ name: "Ada", tags: ["a", "b"] }), "EX", 3600);
const user = fromUpstash(await redis.get("user:1"));
await redis.hset("profile:1", { name: "Ada", age: 36 });
const profile = Object.fromEntries(
Object.entries(await redis.hgetall("profile:1")).map(([k, v]) => [k, fromUpstash(v)]),
);
await redis.pipeline().incr("visits").expire("visits", 86400).exec();
Writing objects with JSON.stringify keeps them readable by any code still on
@upstash/redis, so the two can run side by side during the move.
Node.js: @upstash/redis to node-redis
import fs from "node:fs";
import { createClient } from "redis";
const redis = createClient({
url: "rediss://your-name.cloud.kividb.io:6380",
username: "kividbapp",
password: process.env.KIVIDB_PASSWORD,
socket: { tls: true, ca: fs.readFileSync("kividb-ca.pem") },
});
await redis.connect();
await redis.set("user:1", JSON.stringify({ name: "Ada" }), { EX: 3600 });
const user = fromUpstash(await redis.get("user:1"));
const board = await redis.zRangeWithScores("board", 0, -1); // [{ value, score }]
Python: upstash-redis to redis-py
# Before
from upstash_redis import Redis
redis = Redis.from_env()
# After
import json, os, redis as redispy
r = redispy.Redis(
host="your-name.cloud.kividb.io",
port=6380,
username="kividbapp",
password=os.environ["KIVIDB_PASSWORD"],
ssl=True,
ssl_ca_certs="kividb-ca.pem",
decode_responses=True,
)
r.set("user:1", json.dumps({"name": "Ada"}), ex=3600)
user = json.loads(r.get("user:1"))
Two more differences when you leave REST behind: