Skip to content

Upstash Redis SDK

Use the @upstash/redis methods for the supported Redis commands. HTTP clients and disk scripts share the selected Redis namespace with the virtual CLI.

Create the demo disk and a project API key in the quickstart.

Terminal window
npm install @upstash/redis@1.39.0
External HTTP client
import { Redis } from '@upstash/redis';
const redis = new Redis({
url: "https://api.wabe.sh/v1/disks/demo/redis/app",
token: "YOUR_PROJECT_API_KEY",
});
await redis.set('config', {workers: 4});
console.log(await redis.get('config'));
console.log(await redis.incr('processed'));

The compatibility checks use version 1.39.0. Auto-pipelining and base64 response encoding work with the SDK’s defaults. Configure the SDK’s retry policy explicitly for non-idempotent operations: a lost response can follow a completed INCR or list pop.

Use redis.exec([...]) for supported commands or options without a named SDK method, such as redis.exec(['DELEX', 'key', 'IFEQ', 'expected']).

wabe Disk script
const {Redis} = await import('@upstash/redis');
const redis = new Redis({namespace: 'app'});
await redis.hset('task:1', {title: 'Check storage', attempts: 0});
await redis.hincrby('task:1', 'attempts', 1);
print(await redis.hgetall('task:1'));
await redis.sadd('workers', 'alice', 'bob');
print(await redis.sismember('workers', 'alice'));
await redis.zadd('scheduled', {score: 100, member: 'task:1'});
print(await redis.zrange('scheduled', 0, 200, {byScore: true, withScores: true}));

hgetall deserializes fields into an object and returns null for a missing hash. hmget('key', 'a', 'b') returns an object keyed by the requested fields. Sorted-set replies with scores, including zpopmin, use alternating members and scores. The SDK’s automatic deserialization converts numeric score strings to numbers.

Scan larger keyspaces without collecting every page:

wabe Disk script
const {Redis} = await import('@upstash/redis');
const redis = new Redis({namespace: 'app'});
let cursor = '0';
do {
const page = await redis.scan(cursor, {match: 'task:*', type: 'hash', count: 100});
cursor = page[0];
for (const key of page[1]) print(key);
} while (cursor !== '0');

Pass cursors unchanged as strings. COUNT is a hint, and empty pages can have a nonzero cursor. hscan and sscan use the same iteration pattern. Collection fields and members are limited to 16 KiB; hash values have the 1 MiB value limit. Whole-collection reads and transaction replies must fit the documented response budget.

The isolated runtime includes a bundled @upstash/redis 1.39.0 module. Construct it with a namespace; it uses local broker RPC on the current disk:

wabe Disk script
import { Redis } from '@upstash/redis';
const redis = new Redis({namespace: 'app'});
await redis.rpush('jobs', 'first', 'second');
print(await redis.lpop('jobs'));
print(await redis.incr('processed'));

Save this source on the disk and run qjs /scripts/jobs.js. A source with static imports runs as an ES module: top-level await works, and its execution result is null. Use print for output.

An async-body script can dynamically import the same module and return a value:

wabe Disk script
const {Redis} = await import('@upstash/redis');
const redis = new Redis({namespace: 'app'});
return await redis.get('processed');

The local constructor accepts namespace (default default), automaticDeserialization, enableAutoPipelining, or a custom SDK Requester. URL/token connection options are unavailable inside the worker. The module adds no network access or general npm/file module loading. Lua/script helpers and Pub/Sub remain unavailable.

Request and response data cross IPC in 16 KiB chunks. Retained requests and responses share the invocation’s 8 MiB KV staging budget with KV readers, writers and batches. The worker’s existing memory and execution limits still apply. GET and range results materialize in the JavaScript heap.

wabe Disk script
const {Redis} = await import('@upstash/redis');
const redis = new Redis({namespace: 'app'});
print(await redis.pipeline().set('attempts', 0).incr('attempts').exec());
print(await redis.multi().incr('attempts').get('attempts').exec());

Pipeline commands can interleave with other clients. Multi executes the group in isolation. Runtime errors preserve successful commands; inspect exec({keepErrors:true}) when individual error results are required. SDK JSON serialization/deserialization is client behavior; Redis itself stores byte strings.

Terminal window
redis --namespace app INCR processed
printf 'payload' | redis --namespace app -x SET message
redis --namespace app <<'REDIS'
MULTI
RPUSH jobs first second
LLEN jobs
EXEC
REDIS

redis-cli is an alias for redis. Both are embedded commands. With no command argument they read quoted commands from stdin. --pipe reads binary RESP arrays. --json formats command results as JSON, and --raw selects raw replies. -e returns a nonzero status for command errors; pipe mode also fails when a command fails. These commands open no network connection. A command file is a sequence of commands with per-command atomicity; MULTI/EXEC bounds an explicit transaction to one invocation. Unfinished transactions are discarded.