### Manual QStash Dev Server Setup Source: https://github.com/upstash/skills/blob/main/skills/upstash-qstash-js/fundamentals/local-development.md Manually start the QStash CLI dev server using `npx @upstash/qstash-cli dev`. Then, configure the client with the printed `baseUrl` and `token`, ensuring `devMode` is unset or false. ```bash npx @upstash/qstash-cli dev ``` -------------------------------- ### Combined Agent Setup Example Source: https://github.com/upstash/skills/blob/main/skills/upstash-workflow-js/agents.md This example demonstrates the setup of multiple agents, including models, tools, and tasks, within a single Upstash Workflow JS application. It shows how to define specialized agents and a manager task to orchestrate their execution. ```typescript export const { POST } = serve(async (context) => { const agents = agentWorkflow(context); const model = agents.openai("gpt-4o"); const mathTool = tool({ description: "Compute math", parameters: z.object({ expression: z.string() }), execute: async ({ expression }) => mathjs.evaluate(expression), }); const researcher = agents.agent({ model, name: "researcher", maxSteps: 2, background: "Research topics using wiki.", tools: { wikiTool }, }); const mathematician = agents.agent({ model, name: "math", maxSteps: 2, background: "Solve numeric problems.", tools: { mathTool }, }); const task = agents.task({ model, // manager agents: [researcher, mathematician], maxSteps: 3, prompt: "Tell me about 3 stars and compute the sum of their masses.", }); return (await task.run()).text; }); ``` -------------------------------- ### Basic Rate Limiter Setup and Usage Source: https://github.com/upstash/skills/blob/main/skills/upstash-ratelimit-js/SKILL.md Installs the SDK, connects to Redis, creates a sliding window rate limiter, and applies it to an operation. Use this for a quick start to protect your API endpoints. ```typescript import { Ratelimit } from "@upstash/ratelimit"; import { Redis } from "@upstash/redis"; const redis = new Redis({ url: "", token: "" }); const limiter = new Ratelimit({ redis, limiter: Ratelimit.slidingWindow(5, "10s") }); const { success } = await limiter.limit("user-id"); if (!success) { // throttled } ``` -------------------------------- ### Install QStash JS SDK Source: https://github.com/upstash/skills/blob/main/skills/upstash-qstash-js/SKILL.md Install the QStash JavaScript SDK using npm. This is the first step to using the SDK in your project. ```bash npm install @upstash/qstash ``` -------------------------------- ### Install Upstash Skills via Context7 CLI Source: https://github.com/upstash/skills/blob/main/README.md Install the Upstash skills using the Context7 CLI. ```bash npx ctx7 skills install upstash/skills ``` -------------------------------- ### Install @upstash/box SDK Source: https://github.com/upstash/skills/blob/main/skills/upstash-box-js/SKILL.md Install the SDK using npm. Ensure UPSTASH_BOX_API_KEY is set or passed to constructors. ```bash npm install @upstash/box ``` -------------------------------- ### Full Flow Control Example with All Parameters Source: https://github.com/upstash/skills/blob/main/skills/upstash-workflow-js/features/flow-control.md Demonstrates defining all flow control parameters together: a shared grouping key, maximum concurrent tasks, maximum starts per minute, and the time window for the rate limit. ```typescript import { Client } from "@upstash/workflow"; const client = new Client({ token: "" }); await client.trigger({ url: "https:///process", flowControl: { key: "media-processing", // Shared grouping key parallelism: 4, // Max 4 at the same time rate: 10, // Max 10 starts period: "60s", // in 60 seconds }, }); ``` -------------------------------- ### Example Usage with All Cost-Impacting Features Enabled Source: https://github.com/upstash/skills/blob/main/skills/upstash-ratelimit-js/pricing-cost.md This example demonstrates how to configure and use the Ratelimit class with all optional features enabled, including sliding window, analytics, protection (deny list), and dynamic limits. It shows how to handle rate-limited responses and retrieve remaining requests. ```typescript import { Ratelimit } from "@upstash/ratelimit"; import { Redis } from "@upstash/redis"; const redis = new Redis({ url: process.env.UPSTASH_URL!, token: process.env.UPSTASH_TOKEN! }); const limiter = new Ratelimit({ redis, limiter: Ratelimit.slidingWindow(10, "60 s"), analytics: true, // adds +1 ZINCRBY per call enableProtection: true, // adds +2 per call dynamicLimits: true // adds +1 per call }); async function handle(ip) { const { success, reset } = await limiter.limit(ip); if (!success) { return { status: 429, retryAfter: reset - Date.now() }; } const remaining = await limiter.getRemaining(ip); return { status: 200, remaining }; } ``` -------------------------------- ### Install Upstash Skills via Agent Skills CLI Source: https://github.com/upstash/skills/blob/main/README.md Install the Upstash skills using the Agent Skills CLI. ```bash npx skills add upstash/skills ``` -------------------------------- ### Install Upstash Plugin for Claude Code Source: https://github.com/upstash/skills/blob/main/README.md Add the Upstash skills marketplace and install the plugin for Claude Code. ```bash # Add the marketplace /plugin marketplace add upstash/skills # Install the plugin /plugin install upstash@upstash ``` -------------------------------- ### Verifying Multi-Region Setup with tsx Source: https://github.com/upstash/skills/blob/main/skills/upstash-qstash-js/advanced/multi-region/summary.md Run this command in your terminal to execute a verification script that checks your multi-region environment variable setup. Ensure you have tsx installed globally or locally. ```bash npx tsx skills/advanced/multi-region/verify-multi-region-setup.ts ``` -------------------------------- ### Verify Multi-Region Setup with Bun Source: https://github.com/upstash/skills/blob/main/skills/upstash-qstash-js/advanced/multi-region/summary.md Run this command using Bun to automatically load environment variables and execute the verification script. ```bash # Option 1: Using bun (automatically loads .env) bun run skills/advanced/multi-region/verify-multi-region-setup.ts ``` -------------------------------- ### Install Upstash Search TS SDK Source: https://github.com/upstash/skills/blob/main/skills/upstash-search-js/SKILL.md Install the Upstash Search TypeScript SDK using npm. This is the first step to using the SDK in your project. ```bash npm install @upstash/search ``` -------------------------------- ### Install Upstash CLI Source: https://github.com/upstash/skills/blob/main/skills/upstash-cli/SKILL.md Install the Upstash CLI globally using npm. This command is required before using any other `upstash` commands. ```bash npm i -g @upstash/cli ``` -------------------------------- ### Install QStash SDK Source: https://github.com/upstash/skills/blob/main/skills/upstash-qstash-js/advanced/multi-region/summary.md Update your project dependencies to the latest version of the Upstash QStash SDK to ensure compatibility with multi-region features. ```bash npm install @upstash/qstash@latest # or if using workflows npm install @upstash/qstash@latest @upstash/workflow@latest ``` -------------------------------- ### Install Upstash Redis SDK Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/SKILL.md Install the Upstash Redis SDK using npm. This command is used to add the necessary package to your project for serverless Redis operations. ```bash npm install @upstash/redis ``` -------------------------------- ### Verify Multi-Region Setup with tsx and dotenv Source: https://github.com/upstash/skills/blob/main/skills/upstash-qstash-js/advanced/multi-region/summary.md Use this command with tsx and dotenv to run the verification script, ensuring environment variables are loaded. ```bash # Option 2: Using tsx with dotenv npm install dotenv npx tsx -r dotenv/config skills/advanced/multi-region/verify-multi-region-setup.ts ``` -------------------------------- ### Box Lifecycle Management Source: https://github.com/upstash/skills/blob/main/skills/upstash-box-js/SKILL.md Demonstrates how to create, retrieve, list, pause, resume, and delete Upstash Box instances. It also shows how to get the status of a box. ```APIDOC ## Box Lifecycle Management ### Description Manage the lifecycle of your Upstash Box instances, including creation, retrieval, listing, pausing, resuming, and deletion. You can also check the current status of a box. ### Methods - **`Box.create(options)`**: Creates a new sandboxed container with specified runtime, agent, git, environment variables, and skills. - **`Box.get(boxId)`**: Retrieves an existing Box instance by its ID. - **`Box.list()`**: Fetges a list of all available Box instances. - **`box.pause()`**: Pauses the execution of a running Box instance. - **`box.resume()`**: Resumes a paused Box instance. - **`box.delete()`**: Irreversibly deletes a Box instance. - **`box.getStatus()`**: Retrieves the current status of the Box instance. ### Example ```ts import { Box, Agent, ClaudeCode, BoxApiKey } from "@upstash/box" // Create a new box const box = await Box.create({ runtime: "node", // "node" | "python" | "golang" | "ruby" | "rust" agent: { provider: Agent.ClaudeCode, // Agent.Codex | Agent.OpenCode model: ClaudeCode.Sonnet_4_5, apiKey: BoxApiKey.UpstashKey, // Or BoxApiKey.StoredKey, or "sk-..." }, git: { token: process.env.GITHUB_TOKEN, userName: "Bot", userEmail: "bot@example.com", }, env: { DATABASE_URL: "..." }, skills: ["upstash/qstash-js"], }) // Reconnect to an existing box const same = await Box.get(box.id) // List all boxes const all = await Box.list() // Control box state await box.pause() await box.resume() await box.delete() // irreversible // Get box status const { status } = await box.getStatus() ``` ``` -------------------------------- ### Create and Query Index with node-redis (TCP) Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/search/adapters.md This example shows how to use the @upstash/search-redis adapter with node-redis for TCP connections. Ensure REDIS_URL is set in your environment. ```typescript import { createClient } from "redis"; import { createSearch, s } from "@upstash/search-redis"; const client = createClient({ url: process.env.REDIS_URL }); await client.connect(); const search = createSearch(client); const index = await search.createIndex({ name: "products", prefix: "product:", dataType: "json", schema: s.object({ name: s.string(), price: s.number("F64") }), }); const results = await index.query({ filter: { name: { $eq: "laptop" } }, select: { name: true, price: true }, }); await client.disconnect(); ``` -------------------------------- ### Create Receiver Instance Source: https://github.com/upstash/skills/blob/main/skills/upstash-qstash-js/verification/receiver.md Instantiate the Receiver with your current and next signing keys loaded from environment variables. This setup is crucial for enabling signature verification. ```typescript import { Receiver } from "@upstash/qstash"; const receiver = new Receiver({ currentSigningKey: process.env.QSTASH_CURRENT_SIGNING_KEY!, nextSigningKey: process.env.QSTASH_NEXT_SIGNING_KEY!, }); ``` -------------------------------- ### Set and Get Strings, Numbers, and Objects Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/data-structures/strings.md Demonstrates setting and retrieving string, number, and object values using automatic serialization. Ensure the Redis client is initialized. ```typescript import { Redis } from "@upstash/redis"; const redis = Redis.fromEnv(); // Set and get strings await redis.set("greeting", "Hello World"); const greeting = await redis.get("greeting"); // "Hello World" // Set and get numbers (automatic serialization) await redis.set("views", 100); const views = await redis.get("views"); // 100 (as number, not string) // Set and get objects (automatic JSON serialization) await redis.set("user", { name: "Alice", age: 30 }); const user = await redis.get("user"); // { name: "Alice", age: 30 } ``` -------------------------------- ### Register QStash Dev Server for Next.js Edge Runtimes Source: https://github.com/upstash/skills/blob/main/skills/upstash-qstash-js/fundamentals/local-development.md Call `registerQStashDev()` in `instrumentation.ts` to ensure the QStash dev server starts during Next.js startup, which is necessary for routes in the Edge Runtime. ```typescript // instrumentation.ts import { registerQStashDev } from "@upstash/qstash/nextjs"; export function register() { registerQStashDev(); } ``` -------------------------------- ### Create and Manage a Box Instance Source: https://github.com/upstash/skills/blob/main/skills/upstash-box-js/SKILL.md Demonstrates creating a Box instance with runtime, agent, git, environment variables, and skills. Also shows how to reconnect, list, pause, resume, and delete boxes. ```typescript import { Box, Agent, ClaudeCode, BoxApiKey } from "@upstash/box" // Create with agent + git + env vars const box = await Box.create({ runtime: "node", // "node" | "python" | "golang" | "ruby" | "rust" agent: { provider: Agent.ClaudeCode, // Agent.Codex | Agent.OpenCode model: ClaudeCode.Sonnet_4_5, // apiKey options: // omit → server decides which key to use // BoxApiKey.UpstashKey → use Upstash-provided LLM key // BoxApiKey.StoredKey → use key previously stored via Upstash Console // "sk-..." → direct API key string apiKey: BoxApiKey.UpstashKey, }, git: { // all fields optional token: process.env.GITHUB_TOKEN, // alternatively link your GitHub account via Upstash Console userName: "Bot", userEmail: "bot@example.com", }, env: { DATABASE_URL: "..." }, skills: ["upstash/qstash-js"], // GitHub repos as agent skills }) // Reconnect, list, delete, pause/resume const same = await Box.get(box.id) const all = await Box.list() await box.pause() await box.resume() await box.delete() // irreversible const { status } = await box.getStatus() ``` -------------------------------- ### Initialize QStash Client with Manual Dev Server Credentials Source: https://github.com/upstash/skills/blob/main/skills/upstash-qstash-js/fundamentals/local-development.md When using a manually started dev server, construct the QStash Client by providing the `baseUrl` and `token` obtained from the CLI output. Ensure `devMode` is explicitly set to `false` or omitted. ```typescript const client = new Client({ baseUrl: "http://127.0.0.1:8080", token: "eyJVc2VySUQiOiJkZWZhdWx0VXNlciIsIlBhc3N3b3JkIjoiZGVmYXVsdFBhc3N3b3JkIn0=", }); ``` -------------------------------- ### Upstash Redis JS: Expiration Commands Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/SKILL.md Examples of SETEX for setting a key with an expiration time, EXPIRE to set TTL on an existing key, and TTL to get the remaining time-to-live. ```typescript // Expiration await redis.setex("session", 3600, { userId: "123" }); await redis.expire("key", 60); await redis.ttl("key"); ``` -------------------------------- ### Compare Individual vs. Batch Get Operations Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/performance/batching-operations.md Illustrates the difference in network round trips between fetching multiple keys individually versus using MGET for batch retrieval. ```typescript // Compare: individual operations (3 round trips) const u1 = await redis.get("user:1"); const u2 = await redis.get("user:2"); const u3 = await redis.get("user:3"); // vs batch operation (1 round trip) const users = await redis.mget("user:1", "user:2", "user:3"); ``` -------------------------------- ### Set and Get JSON Document Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/data-structures/json.md Initialize a JSON document in Redis and retrieve its entire content. Ensure the Redis client is configured via environment variables. ```typescript import { Redis } from "@upstash/redis"; const redis = Redis.fromEnv(); // Set entire JSON document await redis.json.set("user:1", "$", { name: "Alice", age: 30, email: "alice@example.com", address: { city: "New York", country: "USA", zip: "10001", }, hobbies: ["reading", "coding"], metadata: { registered: "2024-01-15", verified: true, }, }); // Get entire document const user = await redis.json.get("user:1"); // Returns the full object ``` -------------------------------- ### List Upstash Redis Databases Source: https://github.com/upstash/skills/blob/main/skills/upstash-cli/SKILL.md List all available Upstash Redis databases associated with your account. This command helps in getting an overview of your Redis instances. ```bash upstash redis list ``` -------------------------------- ### Single-Region Setup (Default) Source: https://github.com/upstash/skills/blob/main/skills/upstash-qstash-js/advanced/multi-region/summary.md Configure environment variables for a single-region deployment, primarily for the EU region. This includes setting the API token and optional signing keys for incoming message verification. ```bash # Outgoing messages QSTASH_TOKEN="your_token" # Incoming message verification (optional) QSTASH_CURRENT_SIGNING_KEY="your_current_key" QSTASH_NEXT_SIGNING_KEY="your_next_key" ``` ```bash QSTASH_URL="https://qstash.upstash.io" # EU region (default) QSTASH_TOKEN="your_token" QSTASH_CURRENT_SIGNING_KEY="your_current_key" QSTASH_NEXT_SIGNING_KEY="your_next_key" ``` -------------------------------- ### Multi-Region Setup (US Primary) Source: https://github.com/upstash/skills/blob/main/skills/upstash-qstash-js/advanced/multi-region/summary.md Set up environment variables for a multi-region deployment with the US East 1 region as primary. This involves defining the primary region, region-specific URLs and tokens for both US and EU regions, and optional signing keys. ```bash # Enable multi-region mode with US as primary QSTASH_REGION="US_EAST_1" # Outgoing messages - US region (primary) US_EAST_1_QSTASH_URL="https://qstash-us-east-1.upstash.io" US_EAST_1_QSTASH_TOKEN="your_us_token" # Outgoing messages - EU region (only needed for Upstash Workflow) EU_CENTRAL_1_QSTASH_URL="https://qstash.upstash.io" EU_CENTRAL_1_QSTASH_TOKEN="your_eu_token" # (Optional) Incoming message verification - US region US_EAST_1_QSTASH_CURRENT_SIGNING_KEY="your_us_current_key" US_EAST_1_QSTASH_NEXT_SIGNING_KEY="your_us_next_key" # (Optional) Incoming message verification - EU region EU_CENTRAL_1_QSTASH_CURRENT_SIGNING_KEY="your_eu_current_key" EU_CENTRAL_1_QSTASH_NEXT_SIGNING_KEY="your_eu_next_key" ``` -------------------------------- ### Start ngrok HTTP Tunnel Source: https://github.com/upstash/skills/blob/main/skills/upstash-workflow-js/how-to/local-dev.md Start an ngrok tunnel to expose your local server (e.g., running on port 3000) to the public internet. ```bash ngrok http 3000 ``` -------------------------------- ### Initialize @upstash/ratelimit for Production Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/patterns/rate-limiting.md Demonstrates how to initialize fixed window, sliding window, and token bucket limiters using the `@upstash/ratelimit` library for production use. ```typescript // Production: Use @upstash/ratelimit // npm install @upstash/ratelimit import { Ratelimit } from "@upstash/ratelimit"; // Fixed window const fixedWindowLimiter = new Ratelimit({ redis, limiter: Ratelimit.fixedWindow(10, "60 s"), }); // Sliding window const slidingWindowLimiter = new Ratelimit({ redis, limiter: Ratelimit.slidingWindow(10, "60 s"), }); // Token bucket const tokenBucketLimiter = new Ratelimit({ redis, limiter: Ratelimit.tokenBucket(10, "1 s", 10), }); ``` -------------------------------- ### Connection Initialization: ioredis vs @upstash/redis Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/migrations/from-ioredis.md Demonstrates the different ways to initialize connections for ioredis using host/port and for @upstash/redis using REST URL and token, including environment variable support. ```typescript import Redis from "ioredis"; const redis = new Redis({ host: "redis.upstash.io", port: 6379, password: "your-password", }); ``` ```typescript import { Redis } from "@upstash/redis"; const redis = new Redis({ url: process.env.UPSTASH_REDIS_REST_URL!, token: process.env.UPSTASH_REDIS_REST_TOKEN!, }); // Or use environment variables const redis = Redis.fromEnv(); ``` -------------------------------- ### Connection Initialization: node-redis vs @upstash/redis Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/migrations/from-redis-node.md Demonstrates how to initialize connections for both node-redis using socket details and @upstash/redis using environment variables for REST URL and token. ```typescript import { createClient } from "redis"; const redis = createClient({ socket: { host: "redis.upstash.io", port: 6379, }, password: "your-password", }); await redis.connect(); ``` ```typescript import { Redis } from "@upstash/redis"; const redis = new Redis({ url: process.env.UPSTASH_REDIS_REST_URL!, token: process.env.UPSTASH_REDIS_REST_TOKEN!, }); ``` -------------------------------- ### Get Player Rank in Leaderboard Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/patterns/leaderboard.md Use ZREVRANK to get the rank of a specific player in a leaderboard, ordered from highest score to lowest. The rank is 0-based. ```typescript // Get player's rank (0-based, lowest score = rank 0) const rank = await redis.zrevrank("leaderboard:global", "player:123"); // Use zrevrank for highest-first ranking ``` -------------------------------- ### Get Member Rank in Sorted Set Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/data-structures/sorted-sets.md Use ZRANK to get the 0-based rank (position) of a member in ascending order of scores. Use ZREVRANK for descending order. ```typescript // Get rank (position) of member (0-based, lowest score = rank 0) const rank = await redis.zrank("leaderboard", "player3"); // 0 (lowest score) // Get reverse rank (highest score = rank 0) const revRank = await redis.zrevrank("leaderboard", "player1"); // 0 (highest score) ``` -------------------------------- ### Create Index and Insert Sample Data Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/search/commands/aggregating.md Initializes a Redis client, creates a search index for 'orders', and inserts sample JSON data. Ensures the index is ready for aggregation queries. ```typescript import { Redis, s } from "@upstash/redis"; const redis = Redis.fromEnv(); const index = await redis.search.createIndex({ name: "orders", prefix: "order:", dataType: "json", schema: s.object({ product: s.string(), category: s.facet(), price: s.number("F64"), quantity: s.number("U64"), date: s.date(), }), }); // Insert sample data await redis.json.set("order:1", "$", { product: "Laptop", category: "electronics", price: 999.99, quantity: 1, date: "2024-06-15", }); await redis.json.set("order:2", "$", { product: "Mouse", category: "electronics", price: 29.99, quantity: 3, date: "2024-06-16", }); await redis.json.set("order:3", "$", { product: "Desk", category: "furniture", price: 249.99, quantity: 1, date: "2024-07-01", }); await index.waitIndexing(); ``` -------------------------------- ### Get Surrounding Players for Rank Context Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/patterns/leaderboard.md Retrieve players around a specific player's rank to provide context. This involves getting the player's rank first, then fetching a range of members above and below them. ```typescript // Get surrounding players (context ranking) async function getRankContext(playerId: string, range: number = 5) { const rank = await redis.zrevrank("leaderboard:global", playerId); if (rank === null) return null; const start = Math.max(0, rank - range); const end = rank + range; const players = await redis.zrange("leaderboard:global", start, end, { rev: true, withScores: true, }); return players; } ``` -------------------------------- ### Correctly Set and Get Numeric Values with Upstash Redis Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/SKILL.md Use the Upstash Redis SDK to set and get numeric values directly, allowing for automatic serialization and deserialization. Avoid manual parsing by storing numbers as numbers, not strings. ```typescript // ✅ CORRECT - Let the SDK handle it await redis.set("count", 42); // Stored as number const count = await redis.get("count"); const incremented = count + 1; // Just use it ``` -------------------------------- ### Set Up Signing Keys Source: https://github.com/upstash/skills/blob/main/skills/upstash-qstash-js/verification/receiver.md Store your QStash signing keys as environment variables. These are essential for the Receiver to validate incoming request signatures. ```bash QSTASH_CURRENT_SIGNING_KEY="your_current_key" QSTASH_NEXT_SIGNING_KEY="your_next_key" ``` -------------------------------- ### Fixed Window Ratelimit Example Source: https://github.com/upstash/skills/blob/main/skills/upstash-ratelimit-js/algorithms.md Configures a fixed window rate limiter for 10 requests per 10 seconds. Suitable for performance-critical applications where minor boundary inaccuracies are acceptable. ```javascript // 10 requests per 10 seconds const regional = new Ratelimit({ redis: Redis.fromEnv(), limiter: Ratelimit.fixedWindow(10, "10 s"), }); const multi = new MultiRegionRatelimit({ redis: [new Redis({/* auth */}), new Redis({/* auth */})], limiter: MultiRegionRatelimit.fixedWindow(10, "10 s"), }); ``` -------------------------------- ### Sliding Window Ratelimit Example Source: https://github.com/upstash/skills/blob/main/skills/upstash-ratelimit-js/algorithms.md Sets up a sliding window rate limiter for 10 requests per 10 seconds, offering smoother behavior around boundaries. Note that multi-region usage can be inefficient. ```javascript // 10 requests per 10 seconds const regional = new Ratelimit({ redis: Redis.fromEnv(), limiter: Ratelimit.slidingWindow(10, "10 s"), }); // Multi-region is possible but inefficient const multi = new MultiRegionRatelimit({ redis: [new Redis({/* auth */}), new Redis({/* auth */})], limiter: MultiRegionRatelimit.slidingWindow(10, "10 s"), }); ``` -------------------------------- ### Get All Hash Values Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/data-structures/hashes.md Retrieves all values stored within a hash. ```typescript // Get all values const values = await redis.hvals("user:1"); // ["Alice", "alice@example.com", 30] ``` -------------------------------- ### Get All Hash Fields and Values Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/data-structures/hashes.md Retrieves all field-value pairs from a hash. ```typescript // Get all fields and values const user = await redis.hgetall("user:1"); // { name: "Alice", email: "alice@example.com", age: 30 } ``` -------------------------------- ### Get Stream Length Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/data-structures/streams.md Retrieves the total number of entries in a specified stream. ```typescript // Get stream length const length = await redis.xlen("events"); ``` -------------------------------- ### Initialize QStash Client in Dev Mode Source: https://github.com/upstash/skills/blob/main/skills/upstash-qstash-js/fundamentals/local-development.md Instantiate the QStash Client with `devMode: true` to automatically manage the QStash CLI and dev server for local testing. ```typescript import { Client } from "@upstash/qstash"; const client = new Client({ devMode: true }); await client.publishJSON({ url: "https://example.com/webhook", body: { hello: "world" }, }); ``` -------------------------------- ### Get Number of Hash Fields Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/data-structures/hashes.md Returns the number of fields present in a hash. ```typescript // Get number of fields const fieldCount = await redis.hlen("user:1"); // 3 ``` -------------------------------- ### TypeScript Example: Interacting with QStash Workflow DLQ API Source: https://github.com/upstash/skills/blob/main/skills/upstash-workflow-js/rest-api.md Demonstrates listing DLQ items, restarting/resuming specific runs with header overrides, bulk resuming, rerunning failure callbacks, deleting entries, and inspecting flow control. Ensure QSTASH_TOKEN is set in your environment variables. ```typescript import fetch from "node-fetch"; const token = process.env.QSTASH_TOKEN; const base = "https://qstash.upstash.io/v2"; async function example() { // 1. List DLQ items with filters const list = await fetch( `${base}/workflows/dlq?workflowUrl=https://my.app/workflow&fromDate=1700000000000`, { headers: { Authorization: `Bearer ${token}` }, } ).then((r) => r.json()); const firstDlqId = list.messages?.[0]?.dlqId; // 2. Restart or Resume a specific run (headers may override flow control or retries) const restart = await fetch(`${base}/workflows/dlq/restart/${firstDlqId}`, { method: "POST", headers: { Authorization: `Bearer ${token}`, "Upstash-Flow-Control-Key": "my-key", // optional "Upstash-Flow-Control-Value": "parallelism=1", // optional "Upstash-Retries": "3", // optional }, }).then((r) => r.json()); // 3. Bulk resume using filters and cursor handling const bulkResume = await fetch(`${base}/workflows/dlq/resume`, { method: "POST", headers: { Authorization: `Bearer ${token}` }, body: JSON.stringify({ fromDate: 1700000000000, workflowUrl: "https://my.app/workflow", dlqIds: [firstDlqId], // optional; filters also supported }), }).then((r) => r.json()); // 4. Rerun failure callback const callback = await fetch(`${base}/workflows/dlq/callback/${firstDlqId}`, { method: "POST", headers: { Authorization: `Bearer ${token}` }, }).then((r) => r.json()); // 5. Delete a DLQ entry await fetch(`${base}/workflows/dlq/${firstDlqId}`, { method: "DELETE", headers: { Authorization: `Bearer ${token}` }, }); // 6. Inspect Flow-Control const fc = await fetch(`${base}/flowControl/my-key`, { headers: { Authorization: `Bearer ${token}` }, }).then((r) => r.json()); console.log({ list, restart, bulkResume, callback, fc }); } ``` -------------------------------- ### Serve Workflow Endpoint with Options Source: https://github.com/upstash/skills/blob/main/skills/upstash-workflow-js/basics/serve.md Exposes an async route function as an HTTP endpoint using `serve()`. Includes options for payload parsing, validation, QStash client/receiver, URL overrides, environment variables, logging, and telemetry. ```typescript import { serve } from "@upstash/workflow/nextjs"; import { z } from "zod"; import { Client, Receiver } from "@upstash/qstash"; import { loggingMiddleware } from "@upstash/workflow"; type InitialPayload = { foo: string; bar: number }; const payloadSchema = z.object({ foo: z.string(), bar: z.number() }); export const { POST } = serve( async (context) => { const payload = context.requestPayload; await context.run("step-1", async () => `hello ${payload.foo}`); }, { // Runs when the workflow fails after all retries failureFunction: async ({ context, failStatus, failResponse, failHeaders, failStack }) => console.error(failResponse), // Hooks for step lifecycle, run lifecycle, and debug events middlewares: [loggingMiddleware], // Manually parse the initial request payload before workflow execution initialPayloadParser: (raw) => JSON.parse(raw), // Automatically validate + parse the request payload using Zod schema: payloadSchema, // Override the full URL used to schedule subsequent workflow steps url: "https://myapp.com/api/workflow", // Override only the base portion of the inferred URL (keeps the route path) baseUrl: "https://proxy-url.com", // Provide a custom QStash client qstashClient: new Client({ token: process.env.QSTASH_TOKEN! }), // Provide a custom QStash Receiver for verifying that requests come from QStash receiver: new Receiver({ currentSigningKey: process.env.QSTASH_CURRENT_SIGNING_KEY!, nextSigningKey: process.env.QSTASH_NEXT_SIGNING_KEY!, }), // Override environment variables available inside workflow execution env: { QSTASH_URL: "https://qstash.upstash.io", QSTASH_TOKEN: process.env.QSTASH_TOKEN!, }, // Output detailed execution logs to stdout verbose: true, // Disable anonymous telemetry for this workflow endpoint disableTelemetry: true, } ); ``` -------------------------------- ### Get Single Hash Field Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/data-structures/hashes.md Retrieves the value of a specific field from a hash. ```typescript // Get single field const name = await redis.hget("user:1", "name"); // "Alice" ``` -------------------------------- ### Environment Variables for Multi-Region Setup Source: https://github.com/upstash/skills/blob/main/skills/upstash-qstash-js/advanced/multi-region/summary.md Configure your environment variables to support multi-region QStash. This includes existing single-region credentials and new region-specific variables for URLs, tokens, and signing keys. ```bash # Existing (keep these) QSTASH_TOKEN="your_eu_token" QSTASH_CURRENT_SIGNING_KEY="your_eu_current_key" QSTASH_NEXT_SIGNING_KEY="your_eu_next_key" # New multi-region credentials QSTASH_REGION="US_EAST_1" # Set your primary region US_EAST_1_QSTASH_URL="https://qstash-us-east-1.upstash.io" US_EAST_1_QSTASH_TOKEN="your_us_token" US_EAST_1_QSTASH_CURRENT_SIGNING_KEY="your_us_current_key" US_EAST_1_QSTASH_NEXT_SIGNING_KEY="your_us_next_key" EU_CENTRAL_1_QSTASH_URL="https://qstash.upstash.io" EU_CENTRAL_1_QSTASH_TOKEN="your_eu_token" # Can reuse existing EU_CENTRAL_1_QSTASH_CURRENT_SIGNING_KEY="your_eu_current_key" EU_CENTRAL_1_QSTASH_NEXT_SIGNING_KEY="your_eu_next_key" ``` -------------------------------- ### Get All Hash Field Names Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/data-structures/hashes.md Retrieves all field names stored within a hash. ```typescript // Get all field names const fieldNames = await redis.hkeys("user:1"); // ["name", "email", "age"] ``` -------------------------------- ### Create and Manage User Sessions Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/patterns/session-management.md Demonstrates creating, retrieving, updating, extending, and deleting user sessions with a 1-hour expiration. Requires Redis client initialization. ```typescript import { Redis } from "@upstash/redis"; const redis = Redis.fromEnv(); // Create session with 1-hour expiration async function createSession(userId: string, userData: any) { const sessionId = crypto.randomUUID(); await redis.set( `session:${sessionId}`, { userId, ...userData, createdAt: Date.now(), }, { ex: 3600 } // 1 hour TTL ); return sessionId; } // Get session async function getSession(sessionId: string) { const session = await redis.get(`session:${sessionId}`); return session; } // Update session and refresh TTL async function updateSession(sessionId: string, updates: any) { const current = await redis.get(`session:${sessionId}`); if (!current) { throw new Error("Session not found"); } await redis.set( `session:${sessionId}`, { ...current, ...updates, updatedAt: Date.now() }, { ex: 3600 } // Reset TTL ); } // Extend session (refresh TTL without updating data) async function extendSession(sessionId: string) { await redis.expire(`session:${sessionId}`, 3600); } // Delete session (logout) async function deleteSession(sessionId: string) { await redis.del(`session:${sessionId}`); } ``` -------------------------------- ### Get Multiple Hash Fields Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/data-structures/hashes.md Retrieves the values of multiple specified fields from a hash. ```typescript // Get multiple fields const fields = await redis.hmget("user:1", "name", "email"); // ["Alice", "alice@example.com"] ``` -------------------------------- ### Enable Automatic QStash Dev Server Source: https://github.com/upstash/skills/blob/main/skills/upstash-workflow-js/how-to/local-dev.md Set this environment variable to enable the automatic QStash development server. This is the recommended approach for local development. ```bash QSTASH_DEV=true ``` -------------------------------- ### Get List Length and Range Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/data-structures/lists.md Retrieve the number of elements in a list and a sub-range of elements by index. ```typescript // Get list length const length = await redis.llen("tasks"); // 4 // Get range of elements (0-based index, inclusive) const allTasks = await redis.lrange("tasks", 0, -1); // All elements const firstTwo = await redis.lrange("tasks", 0, 1); // ["task3", "task2"] ``` -------------------------------- ### Practical Example: Event Log with Processing Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/data-structures/streams.md Demonstrates a practical use case of Redis Streams for an event log, including adding orders, creating a processing group, and a worker processing and acknowledging messages. ```typescript // Practical example: Event log with processing await redis.xadd("orders", "*", { orderId: "order-123", status: "pending", amount: 99.99, }); // Create processor group await redis.xgroup("orders", { type: "CREATE", group: "order-processors", id: "0", options: { MKSTREAM: true }, }); // Worker reads and processes const orders = await redis.xreadgroup("order-processors", "worker-1", "orders", ">", { count: 1, }); if (orders && orders[0]) { const messages = (orders[0] as any)[1] as Array<{ 0: string; 1: any }>; if (messages && messages.length > 0) { const order = messages[0]; // Process order... console.log("Processing:", order[1]); // Acknowledge when done await redis.xack("orders", "order-processors", order[0]); } } ``` -------------------------------- ### Read from Multiple Streams Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/data-structures/streams.md Reads entries from multiple streams simultaneously, starting from specified IDs for each stream. ```typescript // Read from multiple streams const multi = await redis.xread(["stream1", "stream2"], ["0", "0"]); ``` -------------------------------- ### Get Player Score from Leaderboard Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/patterns/leaderboard.md Use ZSCORE to retrieve the current score of a specific player from the leaderboard. ```typescript // Get player's score const score = await redis.zscore("leaderboard:global", "player:123"); ``` -------------------------------- ### Get Aggregate Vector Index Statistics Source: https://github.com/upstash/skills/blob/main/skills/upstash-cli/SKILL.md Retrieve aggregate statistics across all Upstash Vector indexes in your account. ```bash upstash vector stats ``` -------------------------------- ### Get Upstash Redis Database Statistics Source: https://github.com/upstash/skills/blob/main/skills/upstash-cli/SKILL.md Retrieve statistics for a specific Upstash Redis database using its ID. ```bash upstash redis stats --db-id ``` -------------------------------- ### Token Bucket Ratelimit Example Source: https://github.com/upstash/skills/blob/main/skills/upstash-ratelimit-js/algorithms.md Implements a token bucket rate limiter with a maximum of 10 tokens, refilling 5 tokens every 10 seconds. Ideal for smoothing traffic and allowing controlled bursts. ```javascript // Bucket with max 10 tokens, refilling 5 tokens every 10s const ratelimit = new Ratelimit({ redis: Redis.fromEnv(), limiter: Ratelimit.tokenBucket(5, "10 s", 10), analytics: true, }); ``` -------------------------------- ### Custom Middleware with Initialization Logic Source: https://github.com/upstash/skills/blob/main/skills/upstash-workflow-js/how-to/middleware.md Create a middleware that requires setup logic, such as database connections or client initialization, using the `init` function. The `init` function returns an object containing the event callbacks. ```typescript import { WorkflowMiddleware } from "@upstash/workflow"; const databaseMiddleware = new WorkflowMiddleware({ name: "database-logger", init: async () => { const db = await connectToDatabase(); return { runStarted: async ({ context }) => { await db.insert({ workflowRunId: context.workflowRunId, status: "started" }); }, runCompleted: async ({ context, result }) => { await db.update({ workflowRunId: context.workflowRunId, status: "completed", result }); }, onError: async ({ workflowRunId, error }) => { await db.insert({ workflowRunId, level: "error", message: error.message }); }, }; }, }); ``` -------------------------------- ### Get a Specific URL Group Source: https://github.com/upstash/skills/blob/main/skills/upstash-qstash-js/fundamentals/url-groups.md Fetch details for a single URL group by its name using `client.urlGroups().get`. ```typescript const group = await client.urlGroups().get("payment-webhooks"); console.log(`Created: ${new Date(group.createdAt)}`); console.log(`Updated: ${new Date(group.updatedAt)}`); console.log(`Endpoints: ${group.endpoints.length}`); ``` -------------------------------- ### Create and Query Index with @upstash/redis (HTTP) Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/search/adapters.md Use this snippet for serverless environments. It initializes the Redis client via environment variables and demonstrates creating a JSON index and querying it. ```typescript import { Redis, s } from "@upstash/redis"; const redis = Redis.fromEnv(); const index = await redis.search.createIndex({ name: "products", prefix: "product:", dataType: "json", schema: s.object({ name: s.string(), price: s.number("F64") }), }); const results = await index.query({ filter: { name: { $eq: "laptop" } }, select: { name: true, price: true }, }); ``` -------------------------------- ### Get Consumer Group Information Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/data-structures/streams.md Retrieves information about all consumer groups associated with a stream. Useful for monitoring group status. ```typescript // Get consumer group info const groups = await redis.xinfo("events", { type: "GROUPS" }); // Returns list of consumer groups ``` -------------------------------- ### Get Pending Messages Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/data-structures/streams.md Retrieves details about messages that have been delivered but not yet acknowledged by a consumer group. Useful for monitoring and recovery. ```typescript // Get pending messages (delivered but not acknowledged) const pending = await redis.xpending("events", "processors", "-", "+", 10); // Returns pending entry details ``` -------------------------------- ### Get Last Entries in Reverse Order Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/data-structures/streams.md Retrieves a specified number of the most recent entries from a stream in reverse chronological order. ```typescript const last10 = await redis.xrevrange("events", "+", "-", 10); // Last 10 in reverse ``` -------------------------------- ### Count Members in Score Range Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/data-structures/sorted-sets.md Use ZCOUNT to get the number of members within a specified score range (inclusive). ```typescript // Count members in score range const countInRange = await redis.zcount("leaderboard", 100, 250); // 2 ``` -------------------------------- ### Set Key with TTL and Manage Expiration Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/performance/ttl-expiration.md Demonstrates setting a key with an expiration time in seconds and managing TTL for existing keys. Also shows how to retrieve the remaining TTL. ```typescript import { Redis } from "@upstash/redis"; const redis = Redis.fromEnv(); // Set with expiration (EX = seconds) await redis.set("session:123", { userId: "user1" }, { ex: 3600 }); // Add TTL to existing key await redis.set("key", "value"); await redis.expire("key", 300); // Expire in 5 minutes // Get TTL of a key const ttl = await redis.ttl("key"); console.log(`TTL: ${ttl} seconds`); // Returns: remaining seconds, -1 (no expiry), -2 (key doesn't exist) ``` -------------------------------- ### Enable QStash Dev Mode via Environment Variable Source: https://github.com/upstash/skills/blob/main/skills/upstash-qstash-js/fundamentals/local-development.md Toggle local development mode using environment variables instead of hard-coding `devMode: true` in the client configuration. This provides a safer way to manage dev mode. ```bash QSTASH_DEV=true # or "1" QSTASH_DEV_PORT=8080 # optional, default 8080 ``` -------------------------------- ### Get Sorted Set Information Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/data-structures/sorted-sets.md Retrieve the number of members (ZCARD) or the score of a specific member (ZSCORE) in a sorted set. ```typescript // Get number of members const count = await redis.zcard("leaderboard"); // 3 // Get score of a member const score = await redis.zscore("leaderboard", "player1"); // 300 ``` -------------------------------- ### Get Element by Index Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/data-structures/lists.md Access a specific element in the list using its 0-based index. Negative indices count from the end. ```typescript // Get element by index const first = await redis.lindex("tasks", 0); // "task3" const last = await redis.lindex("tasks", -1); // "task4" ``` -------------------------------- ### Get Queue Details Source: https://github.com/upstash/skills/blob/main/skills/upstash-qstash-js/fundamentals/queues-and-flow-control.md Retrieve information about a specific queue, including its current parallelism, message lag, and paused status. ```typescript // Get queue details const queue = await client.queue({ queueName: "orders" }).get(); console.log(queue.parallelism); console.log(queue.lag); // Messages waiting console.log(queue.paused); ``` -------------------------------- ### Check for Missing QStash Signing Key Environment Variable Source: https://github.com/upstash/skills/blob/main/skills/upstash-qstash-js/verification/platform-specific/nextjs.md Before initializing QStash services, verify that the necessary signing key environment variables (`QSTASH_CURRENT_SIGNING_KEY`) are set. Throw an error if the variable is missing to prevent runtime issues. ```typescript if (!process.env.QSTASH_CURRENT_SIGNING_KEY) { throw new Error("Missing QSTASH_CURRENT_SIGNING_KEY"); } ``` -------------------------------- ### Index JSON Data and Query Source: https://github.com/upstash/skills/blob/main/skills/upstash-redis-js/search/overview.md Demonstrates creating a 'users' index for JSON data, upserting user information using `redis.json.set`, waiting for indexing to complete, and then performing a query. ```typescript // Create the index const index = await redis.search.createIndex({ name: "users", prefix: "user:", dataType: "json", schema: s.object({ name: s.string(), age: s.number("U64") }), }); // Upsert data with regular Redis commands await redis.json.set("user:1", "$", { name: "Alice", age: 30 }); await redis.json.set("user:2", "$", { name: "Bob", age: 25 }); // Wait for the index to process the new data await index.waitIndexing(); // Now you can query const results = await index.query({ filter: { name: { $eq: "Alice" } }, }); ```