Generated banner for Upstash Qstash JS
Generated logo for Upstash Qstash JS

Upstash Qstash JS

UpstashOfficialCreated by Upstash

  • Skill
  • Tool integration
  • Automation and integrations
  • MIT
  • Low risk
  • Has scripts

From the author

Work with the @upstash/qstash TypeScript/JavaScript SDK, an HTTP-based message queue, task scheduler, and background job system for serverless and edge runtimes (Next.js, Vercel, Cloudflare Workers, Deno, Node.js). Use when publishing messages to HTTP endpoints or URL groups, running background jobs without a long-running worker process, scheduling with cron expressions, delaying messages, building FIFO queues with parallelism and flow control, configuring retries and callbacks, handling a dead letter queue (DLQ), deduplicating messages, fanning out to multiple endpoints, verifying QStash webhook signatures (Next.js App Router, Pages Router, and Edge Runtime), running a local QStash dev server, or migrating regions. Also use when the user asks for a serverless cron job, async task queue, job scheduler, delayed delivery, webhook delivery with retries, or event-driven messaging between services.
— the description by Upstash

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

The QStash JavaScript SDK provides a robust interface for interacting with Upstash's HTTP-based messaging and scheduling platform. Designed for serverless and edge environments like Next.js, Cloudflare Workers, and Deno, this skill enables developers to implement asynchronous task processing, cron-style scheduling, and reliable event-driven communication without maintaining persistent worker infrastructure.

What it does

  • Publishes HTTP messages to individual endpoints or URL groups
  • Schedules recurring tasks using cron expressions
  • Manages FIFO queues with configurable parallelism and flow control
  • Verifies incoming webhook signatures for secure communication
  • Handles advanced messaging patterns like retries, callbacks, and dead letter queues
  • Supports message deduplication and multi-region configurations

When to use it

  • When building serverless applications requiring background job processing
  • When you need to schedule delayed or recurring tasks in edge runtimes
  • When implementing event-driven architectures between microservices
  • When you need reliable webhook delivery with automatic retries
  • When you need to ensure ordered message processing with flow control

Advantages

  • Native support for serverless and edge runtimes
  • Simplifies complex background job orchestration
  • Built-in security via webhook signature verification
  • Flexible configuration for retries, delays, and dead letter queues
  • Supports local development workflows

Usage examples

“How do I publish a JSON message to a webhook using QStash?”
The agent provides a code snippet using the Client.publishJSON method, demonstrating how to initialize the client with an environment token and send a payload to a specific URL.
“How can I verify that a webhook request came from QStash?”
The agent explains how to use the Receiver class to validate incoming request signatures, including platform-specific guidance for frameworks like Next.js.

Install

  1. Download the skill as a ZIP:

    https://autogineer.com/agent-skills/upstash/upstash-qstash-js/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip upstash-qstash-js.zip -d .agents/skills

Documentation by Upstash

QStash JavaScript SDK

QStash is an HTTP-based messaging and scheduling solution for serverless and edge runtimes. This skill helps you use the QStash JS SDK effectively.

Bundled docs and source

Before writing or debugging SDK code, check node_modules/@upstash/qstash/docs/ for bundled docs and node_modules/@upstash/qstash/src/ for readable TypeScript source. Read and search the relevant files when present; otherwise use the references in this skill.

When to use this skill

Use this skill when:

  • Publishing HTTP messages to endpoints or URL groups

  • Creating scheduled or delayed message delivery

  • Managing FIFO queues with configurable parallelism

  • Verifying incoming webhook signatures from QStash

  • Implementing callbacks, DLQ handling, or message deduplication

Quick Start

Installing the SDK
npm install @upstash/qstash
Basic Publishing
import { Client } from "@upstash/qstash";

const client = new Client({
  token: process.env.QSTASH_TOKEN!,
});

const result = await client.publishJSON({
  url: "https://my-api.example.com/webhook",
  body: { event: "user.created", userId: "123" },
});

Core Concepts

For fundamental QStash operations, see:

For verifying incoming messages:

  • Receiver Verification - Core signature verification with the Receiver class

  • Platform-Specific Verifiers:

    • Next.js - App Router, Pages Router, and Edge Runtime

For advanced features:

Platform Support

QStash JS SDK works across various platforms:

  • Next.js (App Router and Pages Router)

  • Cloudflare Workers

  • Deno

  • Node.js (v18+)

  • Vercel Edge Runtime

  • SvelteKit, Nuxt, SolidJS, and other frameworks

Note on Workflow SDK: For building complex durable workflows that chain multiple QStash messages together, consider using the separate QStash Workflow SDK (@upstash/workflow). The Workflow SDK empowers you to orchestrate multi-step processes with automatic state management, retries, and fault tolerance. This Skills file focuses on the core QStash messaging SDK.

Best Practices

  • Always verify incoming QStash messages using the Receiver class

  • Use environment variables for tokens and signing keys

  • Set appropriate retry counts and timeouts for your use case

  • Use queues for ordered processing with controlled parallelism

  • Implement DLQ handling for failed message recovery

Files

verification/receiver.md

Receiver - Message Verification

Overview

The Receiver class verifies that incoming requests are genuinely from QStash by validating JWT signatures. This prevents unauthorized requests from reaching your endpoints.

Getting Your Signing Keys

Sign in to the Upstash Console and navigate to your QStash instance to find:

  • Current Signing Key: Active key for signature verification

  • Next Signing Key: Key to use after rotation

Store these as environment variables:

QSTASH_CURRENT_SIGNING_KEY="your_current_key"
QSTASH_NEXT_SIGNING_KEY="your_next_key"

Creating a Receiver Instance

Basic Setup
import { Receiver } from "@upstash/qstash";

const receiver = new Receiver({
  currentSigningKey: process.env.QSTASH_CURRENT_SIGNING_KEY!,
  nextSigningKey: process.env.QSTASH_NEXT_SIGNING_KEY!,
});
Multi-Region Mode

If you're using multi-region QStash (with QSTASH_REGION environment variable set), signature verification requires additional configuration. The SDK automatically detects the region from the upstash-region header and uses region-specific signing keys.

Important: Multi-region signature verification requires careful setup. See Multi-Region Setup for complete details on environment variables, region detection, and verification strategies.

Verifying Incoming Requests

Basic Verification
try {
  await receiver.verify({
    signature: request.headers.get("upstash-signature")!,
    body: await request.text(),
  });

  // Request is valid - process it
  return new Response("OK", { status: 200 });
} catch (error) {
  // Invalid signature
  return new Response("Unauthorized", { status: 401 });
}
With URL Verification

For extra security, verify the request was sent to the correct URL:

await receiver.verify({
  signature: request.headers.get("upstash-signature")!,
  body: await request.text(),
  url: "https://my-api.example.com/webhook",
});
With Clock Tolerance

Handle minor clock differences between servers:

await receiver.verify({
  signature: request.headers.get("upstash-signature")!,
  body: await request.text(),
  clockTolerance: 5, // Allow 5 seconds difference
});

Required Headers

QStash sends these headers with every request:

  • Upstash-Signature: JWT signature to verify

Note: In multi-region mode, QStash also sends an Upstash-Region header. See Multi-Region Setup for details.

Handling Verification Failures

SignatureError

The verify() method throws SignatureError for invalid signatures:

import { Receiver, SignatureError } from "@upstash/qstash";

try {
  await receiver.verify({
    signature: request.headers.get("upstash-signature")!,
    body: await request.text(),
  });
} catch (error) {
  if (error instanceof SignatureError) {
    console.error("Invalid signature:", error.message);
    return new Response("Invalid signature", { status: 401 });
  }
  throw error;
}
Common Failure Reasons
  1. Missing or wrong signing keys

    • Verify keys in Upstash Console match environment variables

  2. Body mismatch

    • Ensure you pass the raw request body (not parsed JSON)

    • Don't modify the body before verification

  3. Expired signature

    • QStash signatures expire after 5 minutes

    • Check server clock is synchronized

    • Use clockTolerance if needed

  4. URL mismatch

    • Ensure the url parameter matches the destination URL

    • Include protocol, domain, and path

Key Rotation

The Receiver supports seamless key rotation:

  1. Verification tries currentSigningKey first

  2. If that fails, tries nextSigningKey

  3. Only throws error if both fail

To rotate keys:

  1. Set new key as QSTASH_NEXT_SIGNING_KEY

  2. Wait for all in-flight requests to complete

  3. Update QSTASH_CURRENT_SIGNING_KEY to the new key

  4. Generate a new QSTASH_NEXT_SIGNING_KEY

Best Practices

Always Verify

Never trust incoming requests without verification:

// ❌ Don't do this
app.post("/webhook", async (req) => {
  const data = await req.json();
  processWebhook(data); // Unverified!
});

// ✅ Do this
app.post("/webhook", async (req) => {
  const body = await req.text();

  await receiver.verify({
    signature: req.headers.get("upstash-signature")!,
    body,
  });

  const data = JSON.parse(body);
  processWebhook(data);
});
Use Environment Variables

Never hardcode signing keys:

// ❌ Don't do this
const receiver = new Receiver({
  currentSigningKey: "sig_abc123...",
});

// ✅ Do this
const receiver = new Receiver({
  currentSigningKey: process.env.QSTASH_CURRENT_SIGNING_KEY!,
  nextSigningKey: process.env.QSTASH_NEXT_SIGNING_KEY!,
});
Read Body Once

Request bodies can only be read once. Save it for reuse:

const body = await request.text();

// Verify with raw body
await receiver.verify({
  signature: request.headers.get("upstash-signature")!,
  body,
});

// Parse after verification
const data = JSON.parse(body);

Platform-Specific Verification

For framework-specific implementations, see:

Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Needs: Needs Node.js

Security

What our scanner noticed· Low risk

  • Scripts that your agent may run

This skill includes scripts that your agent may run. Read them before you use it.

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Created by
Upstash
Publisher
Upstash (Official)
Source
upstash/skills · skills/upstash-qstash-js · commit 9f9e3e5
Licence
MIT License (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by Upstash or Upstash.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download upstash-qstash-js.zip