Master Upstash Suite
Battle-tested skill for upstash, qstash, expert, serverless. Includes structured workflows, validation checks, and reusable patterns for web development.
Upstash Suite
A serverless data platform skill for using Upstash Redis, Kafka, and QStash in serverless and edge environments, covering caching, message queues, rate limiting, and scheduled tasks.
When to Use
Choose Upstash Suite when:
- Adding Redis caching to serverless functions (Vercel, Cloudflare Workers, AWS Lambda)
- Implementing rate limiting, session storage, or leaderboards at the edge
- Building event-driven architectures with managed Kafka
- Scheduling tasks and webhooks with QStash
Consider alternatives when:
- Running on traditional servers — use self-hosted Redis or Kafka
- Needing complex SQL queries — use a relational database
- Building real-time websocket features — use a dedicated real-time service
Quick Start
# Install Upstash packages npm install @upstash/redis @upstash/ratelimit @upstash/kafka @upstash/qstash
import { Redis } from '@upstash/redis'; const redis = Redis.fromEnv(); // Basic key-value operations await redis.set('user:123', JSON.stringify({ name: 'Jane', plan: 'pro' })); await redis.expire('user:123', 3600); // 1 hour TTL const user = await redis.get<string>('user:123'); console.log(JSON.parse(user!)); // Rate limiting import { Ratelimit } from '@upstash/ratelimit'; const ratelimit = new Ratelimit({ redis, limiter: Ratelimit.slidingWindow(10, '60 s'), // 10 requests per minute analytics: true }); async function handleRequest(req: Request) { const ip = req.headers.get('x-forwarded-for') || '127.0.0.1'; const { success, limit, remaining, reset } = await ratelimit.limit(ip); if (!success) { return new Response('Too Many Requests', { status: 429, headers: { 'X-RateLimit-Limit': limit.toString(), 'X-RateLimit-Remaining': remaining.toString(), 'X-RateLimit-Reset': reset.toString() } }); } return new Response('OK'); } // Caching with automatic serialization class UpstashCache { constructor(private redis: Redis, private prefix: string = 'cache') {} async get<T>(key: string): Promise<T | null> { return this.redis.get<T>(`${this.prefix}:${key}`); } async set<T>(key: string, value: T, ttlSeconds: number = 300): Promise<void> { await this.redis.set(`${this.prefix}:${key}`, JSON.stringify(value), { ex: ttlSeconds }); } async getOrSet<T>(key: string, fetcher: () => Promise<T>, ttl: number = 300): Promise<T> { const cached = await this.get<T>(key); if (cached) return cached; const fresh = await fetcher(); await this.set(key, fresh, ttl); return fresh; } async invalidate(pattern: string): Promise<void> { const keys = await this.redis.keys(`${this.prefix}:${pattern}`); if (keys.length > 0) { await this.redis.del(...keys); } } }
Core Concepts
Upstash Product Suite
| Product | Purpose | Protocol | Pricing |
|---|---|---|---|
| Redis | KV store, caching, rate limiting | REST + Redis | Per-request |
| Kafka | Event streaming, message queues | REST + Kafka | Per-message |
| QStash | Scheduled tasks, webhooks | REST | Per-message |
| Vector | Vector similarity search | REST | Per-query |
QStash Scheduled Tasks
import { Client } from '@upstash/qstash'; const qstash = new Client({ token: process.env.QSTASH_TOKEN! }); // Schedule a one-time task await qstash.publishJSON({ url: 'https://myapp.com/api/process', body: { taskId: '123', action: 'send-email' }, delay: 300 // Run after 5 minutes }); // Create a recurring schedule (cron) await qstash.schedules.create({ destination: 'https://myapp.com/api/daily-report', cron: '0 9 * * *', // Every day at 9 AM body: JSON.stringify({ report: 'daily-summary' }) }); // Publish with retry and deduplication await qstash.publishJSON({ url: 'https://myapp.com/api/webhook', body: { event: 'order.completed', orderId: 'ORD-456' }, retries: 3, deduplicationId: 'order-ORD-456' });
Configuration
| Option | Description | Default |
|---|---|---|
UPSTASH_REDIS_REST_URL | Redis REST API endpoint | Required |
UPSTASH_REDIS_REST_TOKEN | Redis authentication token | Required |
UPSTASH_KAFKA_REST_URL | Kafka REST endpoint | Optional |
UPSTASH_KAFKA_REST_TOKEN | Kafka authentication token | Optional |
QSTASH_TOKEN | QStash authentication token | Optional |
QSTASH_CURRENT_SIGNING_KEY | QStash webhook verification key | Optional |
rate_limit_window | Default rate limit window | "60 s" |
cache_ttl | Default cache TTL in seconds | 300 |
Best Practices
- Use
Redis.fromEnv()for configuration to keep credentials out of code and automatically use theUPSTASH_REDIS_REST_URLandUPSTASH_REDIS_REST_TOKENenvironment variables - Implement cache-aside pattern with
getOrSetthat checks cache first and only calls the expensive operation on miss — this pattern handles cache population, TTL management, and race conditions in a single method - Use QStash for serverless scheduled tasks instead of cron jobs because serverless functions cannot run cron schedules; QStash calls your endpoint on schedule with built-in retry and delivery guarantees
- Set appropriate TTLs on all cached data to prevent stale data from persisting; use short TTLs (60-300s) for frequently changing data and longer TTLs (1-24hr) for static reference data
- Enable Ratelimit analytics to monitor rate limit hits and adjust thresholds based on actual usage patterns rather than guessing appropriate limits
Common Issues
Cold start latency with REST protocol: Upstash uses HTTP REST instead of persistent TCP connections, adding ~50-100ms per request compared to traditional Redis. For latency-sensitive operations, use Upstash's Edge caching or pipeline multiple commands in a single HTTP request.
Rate limiter allowing bursts above limit: The sliding window algorithm allows brief bursts at window boundaries. Use the fixedWindow limiter for strict limits, or configure a token bucket limiter for smoother rate limiting that distributes requests evenly across the window.
QStash webhook verification failing: QStash signs webhook payloads for security, and verification fails if the body is parsed or modified before signature checking. Always verify the signature against the raw request body string, not the parsed JSON, and ensure your framework does not strip or modify headers before verification.
Reviews
No reviews yet. Be the first to review this template!
Similar Templates
Full-Stack Code Reviewer
Comprehensive code review skill that checks for security vulnerabilities, performance issues, accessibility, and best practices across frontend and backend code.
Test Suite Generator
Generates comprehensive test suites with unit tests, integration tests, and edge cases. Supports Jest, Vitest, Pytest, and Go testing.
Pro Architecture Workspace
Battle-tested skill for architectural, decision, making, framework. Includes structured workflows, validation checks, and reusable patterns for development.