Set both credentials as Worker secrets/vars (wrangler secret put UPSTASH_REDIS_REST_URL / UPSTASH_REDIS_REST_TOKEN, or via the dashboard) rather than assuming process.env access.
Fastly Compute: import { Redis } from '@upstash/redis/fastly' and construct new Redis({ url, token, backend: <BACKEND_NAME> }) where BACKEND_NAME matches a backend in fastly.toml.
Understand why REST is required: edge/serverless runtimes restrict raw TCP sockets, so the client speaks HTTP(S)/fetch to the REST API rather than opening a Redis TCP connection the way ioredis or node-redis would.
Rely on the default auto-pipelining and batch calls with Promise.all instead of awaiting each command, reducing concurrent outbound fetches — useful since Cloudflare Workers caps simultaneous requests at 6.
Customize retries at construction time if needed: new Redis({ url, token, retry: { retries: 5, backoff: (retryCount) => Math.exp(retryCount) * 50 } }).
On Node.js v17 and earlier, import '@upstash/redis/with-fetch' since native fetch is unavailable there.
For lower edge read latency consider a Global Database: one primary region for writes plus read regions near your functions.
Official docs: https://upstash.com/docs/redis/sdks/ts/getstarted | https://upstash.com/docs/redis/sdks/ts/deployment | https://upstash.com/docs/redis/features/globaldatabase | https://upstash.com/docs/redis/sdks/ts/retries
Known gotchas
TCP Redis clients (ioredis, node-redis) do not work in Cloudflare Workers or Vercel Edge because raw sockets are restricted — the REST-based @upstash/redis client is required.
Cloudflare Workers module syntax requires Redis.fromEnv(env) with env passed explicitly; the no-argument form only works in the older service-worker format.
Awaiting every call one at a time in a Worker defeats default auto-pipelining and can push against Cloudflare's cap of 6 simultaneous outbound requests under load.
A Global Database routes ALL writes to the single primary region regardless of where the edge function runs, so it is documented as a poor fit for write-heavy workloads.
Global Database replication is asynchronous — a read can return a stale value while a write for the same key is still propagating to read replicas.
On Node.js v17 and earlier the default import fails because fetch is not built in; use '@upstash/redis/with-fetch'.
SDK calls still inherit REST limits (10MB max request size), so large values or batches must be chunked even when using the SDK.
Give your agent this knowledge — and 16,000+ more routes
One MCP install gives any agent live access to the full route map across 5,800+ domains, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp
Need this verified for your stack — or a route we don't have yet?