# @upstash/redis: a Redis client that speaks HTTP

> The Upstash Redis client for TypeScript replaces the Redis TCP protocol with REST calls, which makes it usable from serverless functions, edge workers and browsers. It covers the everyday command surface and ships a documented release pipeline, and it is tied to an HTTP-facing Redis service rather than to any Redis server you host yourself.

**upstash/redis-js** — HTTP based Redis Client for Serverless and Edge Functions

- Repository: https://github.com/upstash/redis-js
- Website: https://docs.upstash.com/redis
- Stars: 982 · Forks: 99
- Language: TypeScript
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/upstash-redis-js

## The protocol change is the whole point

@upstash/redis is an HTTP and REST based Redis client for TypeScript, built on top of the Upstash REST API. The README calls it the only connectionless, HTTP based Redis client, and that claim is what defines the library.

Every command becomes an HTTP request carrying a token and a URL instead of a write to a socket. That single change is what unlocks the environments the README lists: serverless functions such as AWS Lambda, Cloudflare Workers, Fastly Compute@Edge, Next.js and Jamstack setups, client side web and mobile applications, and WebAssembly. In all of them, a long lived TCP connection to Redis is either impossible or undesirable, and an HTTP request is something the platform already knows how to make.

The cost of that choice is a connection model you have to think about. There is no socket to keep warm, and no pipeline of commands multiplexed on one connection in the way a TCP client would give you. What you get instead is a client that works the same in every one of those environments, including the browser, where a Redis socket is simply not an option.

The project is in GA stage according to the README, which also states that the Upstash Professional Support fully covers it and that the team is committed to maintaining it.

The audience is therefore application developers deploying to serverless or edge platforms, not operators of a Redis cluster.

## Installing for Node.js and Deno

The Node.js install is a normal npm dependency:

```bash
npm install @upstash/redis
```

For Deno there is no install step, because the package is imported directly from a CDN URL:

```ts
import { Redis } from "https://esm.sh/@upstash/redis";
```

That import line is a good illustration of the library's design. Nothing about the client assumes a package registry or a bundler, and a runtime with an HTTP client and a module loader is enough.

The remaining setup is a database. The README tells you to create a new Redis database in the Upstash console and copy the URL and token, and those two values are the only configuration the client needs.

There is a shortcut for trying it out. The README points out that you can skip the signup and dashboard by POSTing to https://upstash.com/start-redis, which returns an endpoint and a token in a single HTTP request. The database expires after 72 hours unless you claim it with your Upstash account, and the README suggests it is especially useful for AI agents that need scratch storage on the fly.

A scratch database with a 72 hour life is a genuinely useful evaluation tool here, since the only thing you need to test is a URL and a token.

## The everyday command surface, in one example

The basic usage example in the README covers the five data types most projects touch, which is a good way to see the API shape.

```ts
import { Redis } from "@upstash/redis"

const redis = new Redis({
  url: <UPSTASH_REDIS_REST_URL>,
  token: <UPSTASH_REDIS_REST_TOKEN>,
})

// string
await redis.set('key', 'value');
let data = await redis.get('key');
console.log(data)

await redis.set('key3', 'value3', {ex: 1});

// sorted set
await redis.zadd('scores', { score: 1, member: 'team1' })
data = await redis.zrange('scores', 0, 100 )
console.log(data)

// list
await redis.lpush('elements', 'magnesium')
data = await redis.lrange('elements', 0, 100 )
console.log(data)

// hash
await redis.hset('people', {name: 'joe'})
data = await redis.hget('people', 'name' )
console.log(data)

// sets
await redis.sadd('animals', 'cat')
data  = await redis.spop('animals', 1)
console.log(data)
```

Three details are worth pulling out. The set call takes an options object, so an expiry is expressed as {ex: 1} rather than a separate command. The hash and sorted set writes take a plain object or a score and member map rather than repeated key value arguments. And the reads return the value directly rather than a raw reply, with the type coercion handled for you.

The README does not enumerate the full command list. It points to the Redis compatibility page for the list of supported APIs, which is where you should check before relying on a specific command, and the repository's examples folder includes an auto-pipeline example that shows how to batch calls when you want fewer round trips.

## Telemetry is on by default and easy to switch off

The client sends anonymous telemetry, and the README is explicit about what that means. Four things are collected: the SDK version, the platform such as Deno, Cloudflare or Vercel, the runtime version such as node@18.x, and the retry count of retried requests, which is used to measure retry rates.

That last item is the interesting one, because it tells you the client retries failed requests, and the telemetry exists to measure how often that happens. It also means the library has a retry policy you are not configuring, which is worth knowing when you reason about the latency of a call.

Opting out is straightforward. Setting the environment variable UPSTASH_DISABLE_TELEMETRY to any truthy value disables it:

```sh
UPSTASH_DISABLE_TELEMETRY=1
```

Or you can turn it off per client instance:

```ts
const redis = new Redis({
  // ...,
  enableTelemetry: false,
});
```

Both routes are documented, which is more than many libraries offer. The collection is anonymous and limited to the four items above, but a team with a strict policy about outbound calls from production runtimes should still switch it off explicitly rather than assume the default is acceptable.

## The release path is a chain of GitHub workflows

The README documents the release process in unusual detail, which makes it easy to see what happens between a commit and an npm tag.

A stable release starts with a changeset created by pnpm changeset and merged to main. The Changeset workflow then runs on that push, and if changesets are pending it opens a Version Packages pull request. Merging that pull request triggers the workflow again, which publishes git tags, creates GitHub releases and uploads an artifact named release-meta.

A separate Router workflow detects that completion through workflow_run, downloads the release-meta artifact and calls the npm Publish workflow with prerelease set to false and the resolved version. The npm Publish workflow checks out the released commit, builds and publishes to npm under the latest tag.

The canary path mirrors it. Triggering the Canary Release workflow by hand from the Actions tab creates a snapshot version in the form x.y.z-canary.{timestamp}, creates a GitHub prerelease and uploads the same artifact, and the Router picks it up and calls npm Publish with prerelease true so the package lands under the canary tag.

The value of this design for an adopter is that the canary channel exists at all. Being able to install a timestamped snapshot of the next release and test it against your own traffic before it goes to latest is worth more than the extra complexity suggests.

## Tests run on every pull request and on a daily schedule

The CI section of the README says that on every pull request, every push to main, and on a daily schedule, the Router workflow runs the Tests workflow, which covers unit tests, lint, build and example integration tests. Those example integration tests matter, because the examples directory is unusually broad.

Looking at the folders, there is an example for almost every deployment shape a JavaScript project might find itself in: aws-lambda, aws-sam, aws-cdk-typescript, aws-cdk-python, azure-functions, cloudflare-workers, cloudflare-workers-with-typescript, deno, fastapi, fastly, google-cloud-functions, ion, nextjs-app-router, nextjs-pages-router, nodejs, serverless-framework, sst-v2, terraform, vercel-functions-app-router, vercel-functions-pages-router, vercel-python-runtime-django, redis-search and redis-search-analytics, plus auto-pipeline and ai-sdk-telemetry.

That list is a de facto compatibility matrix, and it is verified by the CI rather than maintained as prose.

The local development path uses Bun rather than npm or pnpm for the test and build commands:

```sh
bun run test
```

```sh
bun run build
```

The repository root is a pnpm workspace with packages/ and a pnpm-workspace.yaml, and the root scripts delegate with pnpm -r. Formatting and linting run prettier and eslint, husky installs the git hooks, and there is a commitlint configuration for conventional commit messages.

## Where the HTTP client is the wrong tool

The clearest case against this library is a Redis server you host on a private network, reached from a long running server. There, a TCP client is both faster and simpler, because it keeps a connection open and amortises the handshake over many commands. With HTTP, every command is a fresh request, and you pay for that on every call.

The second limitation is command coverage. The README points to a Redis compatibility page for the supported APIs rather than claiming full coverage, and over REST you will not find every command a Redis server offers. Blocking operations, transactions and server-side scripting are the categories where the difference tends to bite, and the README does not document how each of them behaves in this client. Anyone whose design depends on those semantics should check the compatibility list before committing to the architecture.

The third limitation is the service dependency. The client is built on the Upstash REST API, so it expects an HTTP-facing Redis service. It is not a client for a Redis server you run yourself unless that server exposes the same REST surface, and the README describes no configuration for pointing it at a self-hosted endpoint with different semantics.

The alternative approach for a server-side workload is to use a conventional Redis client over TCP against a Redis server you operate. The difference in approach is the connection model, and it is a real engineering difference rather than a matter of taste: HTTP suits bursty, stateless, edge-deployed code, while a persistent socket suits steady, stateful, long-running code. Pick the client that matches where your code runs, not which one is easier to install.

## Conclusion

Adopt @upstash/redis when your code runs somewhere a TCP socket is unavailable or unwelcome, such as a serverless function, an edge worker or a browser, and where a request per command is acceptable. Skip it when you operate a Redis server on a private network, since a persistent connection is both faster and simpler there. Verify three things before you commit: that the commands you need appear in the Redis compatibility list linked from the README, since HTTP access covers a subset of the server surface, that telemetry is disabled through UPSTASH_DISABLE_TELEMETRY or enableTelemetry: false if your policy forbids it, and that your runtime is covered by the examples, which range from Deno and Cloudflare Workers to Vercel, Fastly, AWS Lambda and Terraform deployments. The last push to main was on 2026-10-14 and the licence is MIT.

## FAQ

### How do I install the Upstash Redis client?

Run npm install @upstash/redis for Node.js. In Deno you can import it directly with import { Redis } from "https://esm.sh/@upstash/redis" and then create a client with the url and token from your Upstash database.

### How do I disable telemetry in @upstash/redis?

Set the UPSTASH_DISABLE_TELEMETRY environment variable to any truthy value, for example UPSTASH_DISABLE_TELEMETRY=1, or pass enableTelemetry: false when constructing the Redis client. The telemetry collects the SDK version, platform, runtime version and retry count.

### Which Redis commands does @upstash/redis support?

The README links to a Redis compatibility page listing the supported APIs rather than enumerating them in the repository. The example code covers strings, sorted sets, lists, hashes and sets, and the repository also includes redis-search and auto-pipeline examples.

### Can I use @upstash/redis on Cloudflare Workers and other edge runtimes?

Yes. The README names Cloudflare Workers, Fastly Compute@Edge, serverless functions, Next.js and Jamstack setups, client side web and mobile applications and WebAssembly among the environments it is designed for, and the examples folder has a folder for each of them.

### How are @upstash/redis releases published?

A changeset merged to main opens a Version Packages pull request, and merging that publishes git tags, GitHub releases and a release-meta artifact that a Router workflow passes to the npm Publish workflow, which publishes to npm under the latest tag. A manual canary workflow publishes snapshot versions under the canary tag.

## Sources

- [License: MIT](https://github.com/upstash/redis-js/blob/main/LICENSE)
- [Project website](https://docs.upstash.com/redis)
- [README](https://github.com/upstash/redis-js/blob/main/README.md)
- [Releases](https://github.com/upstash/redis-js/releases)
- [upstash/redis-js on GitHub](https://github.com/upstash/redis-js)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/upstash-redis-js
