@upstash/query offers secondary indexing and search capabilities for Upstash Redis. It is fully managed by Upstash and scales automatically.



  • E2E Typesafe: Fully typed API with TypeScript generics to offer the best developer experience.
  • Secondary Indexing: Create indexes on your data and query them with a simple API.
  • Range Queries: Query your data with range queries. Either numeric or lexicographic.



Install dependencies

pnpm add @upstash/query @upstash/redis

Set environment variables


Import the packages and create a client

import { Redis } from "@upstash/redis";
// import { Redis } from "@upstash/redis/cloudflare"; // for Cloudflare Workers
// import { Redis } from "@upstash/redis/fastly"; // for Fastly Compute@Edge
import { Query } from "@upstash/query";

const q = new Query({
    // it's important to turn off deserialization 
    // because @upstash/query handles deserialization itself
    redis: Redis.fromEnv({ automaticDeserialization: false }),


Define a type for your data

type User = {
    id: string;
    name: string;
    organization: string;
    email: string;

Create a collection of the same type and an index on the collection

   * Create your first collection.
   * Please make sure you're passing in a type to take full advantage of @upstash/query
  const users = q.createCollection<User>("users");

   * Create a searchable index on the collection and specify which terms we are filtering by
   * terms are fully typed as long as you have defined a custom type when creating the collection
  const usersByOrganization = users.createIndex({
    name: "users_by_organization",
    terms: ["organization"],

It’s important to declare indices before you start adding data to your collection. Otherwise, they will not be indexed. In cases where you want to add an index to an existing collection, you can use the .reIndex() method.


Time to add some data

const user: User = {
  id: "chronark",
  name: "Andreas Thomas",
  organization: "Upstash",
  email: "andreas@upstash.com",
// Create and store your first user
await users.set("documentId", user);


Run your first query against the index

 * Now we can use the previously created index to query by organization
const upstashEmployees = await usersByOrganization.match({
      organization: "Upstash" 
 * [
 *     {
 *         id: "documentId",
 *         ts: 000, // the timestamp when created or last updated
 *         data: {
 *             id: "chronark",
 *             name: "Andreas Thomas",
 *             organization: "Upstash",
 *             email: "andreas@upstash.com"
 *         }
 *     }
 * ]