{"id":"90acf66f-e461-40e1-be68-e3815906be1b","shortId":"UEC8RM","kind":"skill","title":"upstash-qstash","tagline":"Upstash QStash expert for serverless message queues, scheduled","description":"# Upstash QStash\n\nUpstash QStash expert for serverless message queues, scheduled jobs, and\nreliable HTTP-based task delivery without managing infrastructure.\n\n## Principles\n\n- HTTP is the interface - if it speaks HTTPS, it speaks QStash\n- Endpoints must be public - QStash calls your URLs from the cloud\n- Verify signatures always - never trust unverified webhooks\n- Schedules are fire-and-forget - QStash handles the cron\n- Retries are built-in - but configure them for your use case\n- Delays are free - schedule seconds to days in the future\n- Callbacks complete the loop - know when delivery succeeds or fails\n- Deduplication prevents double-processing - use message IDs\n\n## Capabilities\n\n- qstash-messaging\n- scheduled-http-calls\n- serverless-cron\n- webhook-delivery\n- message-deduplication\n- callback-handling\n- delay-scheduling\n- url-groups\n\n## Scope\n\n- complex-workflows -> inngest\n- redis-queues -> bullmq-specialist\n- event-sourcing -> event-architect\n- workflow-orchestration -> temporal-craftsman\n\n## Tooling\n\n### Core\n\n- qstash-sdk\n- upstash-console\n\n### Frameworks\n\n- nextjs\n- cloudflare-workers\n- vercel-functions\n- aws-lambda\n- netlify-functions\n\n### Patterns\n\n- scheduled-jobs\n- delayed-messages\n- webhook-fanout\n- callback-verification\n\n### Related\n\n- upstash-redis\n- upstash-kafka\n\n## Patterns\n\n### Basic Message Publishing\n\nSending messages to be delivered to endpoints\n\n**When to use**: Need reliable async HTTP calls\n\nimport { Client } from '@upstash/qstash';\n\nconst qstash = new Client({\n  token: process.env.QSTASH_TOKEN!,\n});\n\n// Simple message to endpoint\nawait qstash.publishJSON({\n  url: 'https://myapp.com/api/process',\n  body: {\n    userId: '123',\n    action: 'welcome-email',\n  },\n});\n\n// With delay (process in 1 hour)\nawait qstash.publishJSON({\n  url: 'https://myapp.com/api/reminder',\n  body: { userId: '123' },\n  delay: 60 * 60,  // seconds\n});\n\n// With specific delivery time\nawait qstash.publishJSON({\n  url: 'https://myapp.com/api/scheduled',\n  body: { report: 'daily' },\n  notBefore: Math.floor(Date.now() / 1000) + 86400,  // tomorrow\n});\n\n### Scheduled Cron Jobs\n\nSetting up recurring scheduled tasks\n\n**When to use**: Need periodic background jobs without infrastructure\n\nimport { Client } from '@upstash/qstash';\n\nconst qstash = new Client({\n  token: process.env.QSTASH_TOKEN!,\n});\n\n// Create a scheduled job\nconst schedule = await qstash.schedules.create({\n  destination: 'https://myapp.com/api/cron/daily-report',\n  cron: '0 9 * * *',  // Every day at 9 AM UTC\n  body: JSON.stringify({ type: 'daily' }),\n  headers: {\n    'Content-Type': 'application/json',\n  },\n});\n\nconsole.log('Schedule created:', schedule.scheduleId);\n\n// List all schedules\nconst schedules = await qstash.schedules.list();\n\n// Delete a schedule\nawait qstash.schedules.delete(schedule.scheduleId);\n\n### Signature Verification\n\nVerifying QStash message signatures in your endpoint\n\n**When to use**: Any endpoint receiving QStash messages (always!)\n\n// app/api/webhook/route.ts (Next.js App Router)\nimport { Receiver } from '@upstash/qstash';\nimport { NextRequest, NextResponse } from 'next/server';\n\nconst receiver = new Receiver({\n  currentSigningKey: process.env.QSTASH_CURRENT_SIGNING_KEY!,\n  nextSigningKey: process.env.QSTASH_NEXT_SIGNING_KEY!,\n});\n\nexport async function POST(req: NextRequest) {\n  const signature = req.headers.get('upstash-signature');\n  const body = await req.text();\n\n  // ALWAYS verify signature\n  const isValid = await receiver.verify({\n    signature: signature!,\n    body,\n    url: req.url,\n  });\n\n  if (!isValid) {\n    return NextResponse.json(\n      { error: 'Invalid signature' },\n      { status: 401 }\n    );\n  }\n\n  // Safe to process\n  const data = JSON.parse(body);\n  await processMessage(data);\n\n  return NextResponse.json({ success: true });\n}\n\n### Callback for Delivery Status\n\nGetting notified when messages are delivered or fail\n\n**When to use**: Need to track delivery status for critical messages\n\nimport { Client } from '@upstash/qstash';\n\nconst qstash = new Client({\n  token: process.env.QSTASH_TOKEN!,\n});\n\n// Publish with callback\nawait qstash.publishJSON({\n  url: 'https://myapp.com/api/critical-task',\n  body: { taskId: '456' },\n  callback: 'https://myapp.com/api/qstash-callback',\n  failureCallback: 'https://myapp.com/api/qstash-failed',\n});\n\n// Callback endpoint receives delivery status\n// app/api/qstash-callback/route.ts\nexport async function POST(req: NextRequest) {\n  // Verify signature first!\n  const data = await req.json();\n\n  // data contains:\n  // - sourceMessageId: original message ID\n  // - url: destination URL\n  // - status: HTTP status code\n  // - body: response body\n\n  if (data.status >= 200 && data.status < 300) {\n    await markTaskComplete(data.sourceMessageId);\n  }\n\n  return NextResponse.json({ received: true });\n}\n\n### URL Groups (Fan-out)\n\nSending messages to multiple endpoints at once\n\n**When to use**: Need to notify multiple services about an event\n\nimport { Client } from '@upstash/qstash';\n\nconst qstash = new Client({\n  token: process.env.QSTASH_TOKEN!,\n});\n\n// Create a URL group\nawait qstash.urlGroups.addEndpoints({\n  name: 'order-processors',\n  endpoints: [\n    { url: 'https://inventory.myapp.com/api/process' },\n    { url: 'https://shipping.myapp.com/api/process' },\n    { url: 'https://analytics.myapp.com/api/track' },\n  ],\n});\n\n// Publish to the group - all endpoints receive the message\nawait qstash.publishJSON({\n  urlGroup: 'order-processors',\n  body: {\n    orderId: '789',\n    event: 'order.placed',\n  },\n});\n\n### Message Deduplication\n\nPreventing duplicate message processing\n\n**When to use**: Idempotency is critical (payments, notifications)\n\nimport { Client } from '@upstash/qstash';\n\nconst qstash = new Client({\n  token: process.env.QSTASH_TOKEN!,\n});\n\n// Deduplicate by custom ID (within deduplication window)\nawait qstash.publishJSON({\n  url: 'https://myapp.com/api/charge',\n  body: { orderId: '123', amount: 5000 },\n  deduplicationId: 'charge-order-123',  // Won't send again within window\n});\n\n// Content-based deduplication\nawait qstash.publishJSON({\n  url: 'https://myapp.com/api/notify',\n  body: { userId: '456', message: 'Hello' },\n  contentBasedDeduplication: true,  // Hash of body used as ID\n});\n\n## Sharp Edges\n\n### Not verifying QStash webhook signatures\n\nSeverity: CRITICAL\n\nSituation: Endpoint accepts any POST request. Attacker discovers your callback URL.\nFake messages flood your system. Malicious payloads processed as trusted.\n\nSymptoms:\n- No Receiver import in webhook handler\n- Missing upstash-signature header check\n- Processing request before verification\n\nWhy this breaks:\nQStash endpoints are public URLs. Without signature verification, anyone\ncan send requests. This is a direct path to unauthorized message processing\nand potential data manipulation.\n\nRecommended fix:\n\n# Always verify signatures with both keys:\n```typescript\nimport { Receiver } from '@upstash/qstash';\n\nconst receiver = new Receiver({\n  currentSigningKey: process.env.QSTASH_CURRENT_SIGNING_KEY!,\n  nextSigningKey: process.env.QSTASH_NEXT_SIGNING_KEY!,\n});\n\nexport async function POST(req: NextRequest) {\n  const signature = req.headers.get('upstash-signature');\n  const body = await req.text();  // Raw body required\n\n  const isValid = await receiver.verify({\n    signature: signature!,\n    body,\n    url: req.url,\n  });\n\n  if (!isValid) {\n    return NextResponse.json({ error: 'Invalid signature' }, { status: 401 });\n  }\n\n  // Safe to process\n}\n```\n\n# Why two keys?\n- QStash rotates signing keys\n- nextSigningKey becomes current during rotation\n- Both must be checked for seamless key rotation\n\n### Callback endpoint taking too long to respond\n\nSeverity: HIGH\n\nSituation: Webhook handler does heavy processing. Takes 30+ seconds. QStash times out.\nMarks message as failed. Retries. Double processing begins.\n\nSymptoms:\n- Webhook timeouts in QStash dashboard\n- Messages marked failed then retried\n- Duplicate processing of same message\n\nWhy this breaks:\nQStash has a 30-second timeout for callbacks. If your endpoint doesn't respond\nin time, QStash considers it failed and retries. Long-running handlers create\nduplicate message processing and wasted retries.\n\nRecommended fix:\n\n# Design for fast acknowledgment:\n```typescript\nexport async function POST(req: NextRequest) {\n  // 1. Verify signature first (fast)\n  // 2. Parse and validate message (fast)\n  // 3. Queue for async processing (fast)\n\n  const message = await parseMessage(req);\n\n  // Don't do this:\n  // await processHeavyWork(message);  // Could timeout!\n\n  // Do this instead:\n  await db.jobs.create({ data: message, status: 'pending' });\n  // Or use another QStash message for the heavy work\n\n  return NextResponse.json({ queued: true });  // Respond fast\n}\n```\n\n# Alternative: Use QStash for the heavy work\n```typescript\n// Webhook receives trigger\nawait qstash.publishJSON({\n  url: 'https://myapp.com/api/heavy-process',\n  body: { jobId: message.id },\n});\nreturn NextResponse.json({ delegated: true });\n```\n\n# For Vercel: Consider using Edge runtime for faster cold starts\n\n### Hitting QStash rate limits unexpectedly\n\nSeverity: HIGH\n\nSituation: Burst of events triggers mass message publishing. QStash rate limit hit.\nMessages rejected. Users don't get notifications. Critical tasks delayed.\n\nSymptoms:\n- 429 errors from QStash\n- Messages not being delivered\n- Sudden drop in processing during peak times\n\nWhy this breaks:\nQStash has plan-based rate limits. Free tier: 500 messages/day. Pro: higher\nbut still limited. Bursts can exhaust limits quickly. Without monitoring,\nyou won't know until users complain.\n\nRecommended fix:\n\n# Check your plan limits:\n- Free: 500 messages/day\n- Pay as you go: Check dashboard\n- Pro: Higher limits, check dashboard\n\n# Implement rate limit handling:\n```typescript\ntry {\n  await qstash.publishJSON({ url, body });\n} catch (error) {\n  if (error.message?.includes('rate limit')) {\n    // Queue locally and retry later\n    await localQueue.add('qstash-retry', { url, body });\n  }\n  throw error;\n}\n```\n\n# Batch messages when possible:\n```typescript\n// Instead of 100 individual publishes\nawait qstash.batchJSON({\n  messages: items.map(item => ({\n    url: 'https://myapp.com/api/process',\n    body: { itemId: item.id },\n  })),\n});\n```\n\n# Monitor in dashboard:\nUpstash Console shows usage and limits\n\n### Not using deduplication for critical operations\n\nSeverity: HIGH\n\nSituation: Network hiccup during publish. SDK retries. Same message sent twice.\nCustomer charged twice. Email sent twice. Data corrupted.\n\nSymptoms:\n- Duplicate charges or emails\n- Double processing of same event\n- User complaints about duplicates\n\nWhy this breaks:\nNetwork failures and retries happen. Without deduplication, the same logical\nmessage can be sent multiple times. QStash provides deduplication, but you\nmust use it for critical operations.\n\nRecommended fix:\n\n# Use deduplication for critical messages:\n```typescript\n// Custom ID (best for business operations)\nawait qstash.publishJSON({\n  url: 'https://myapp.com/api/charge',\n  body: { orderId: '123', amount: 5000 },\n  deduplicationId: `charge-${orderId}`,  // Same ID = same message\n});\n\n// Content-based (good for notifications)\nawait qstash.publishJSON({\n  url: 'https://myapp.com/api/notify',\n  body: { userId: '456', type: 'welcome' },\n  contentBasedDeduplication: true,  // Hash of body\n});\n```\n\n# Deduplication window:\n- Default: 60 seconds\n- Messages with same ID in window are deduplicated\n- Plan for this in your retry logic\n\n# Also make endpoints idempotent:\nCheck if operation already completed before processing\n\n### Expecting QStash to reach private/localhost endpoints\n\nSeverity: CRITICAL\n\nSituation: Development works with local server. Deploy to production with internal URL.\nQStash can't reach it. All messages fail silently. No processing happens.\n\nSymptoms:\n- Messages show \"failed\" in QStash dashboard\n- Works locally but fails in \"production\"\n- Using http:// instead of https://\n\nWhy this breaks:\nQStash runs in Upstash's cloud. It can only reach public, internet-accessible\nURLs. localhost, internal IPs, and private networks are unreachable. This is\na fundamental architecture requirement, not a configuration issue.\n\nRecommended fix:\n\n# Production requirements:\n- URL must be publicly accessible\n- HTTPS required (HTTP will fail)\n- No localhost, 127.0.0.1, or private IPs\n\n# Local development options:\n\n# Option 1: ngrok/localtunnel\n```bash\nngrok http 3000\n# Use the ngrok URL for QStash testing\n```\n\n# Option 2: QStash local development mode\n```typescript\n// In development, skip QStash and call directly\nif (process.env.NODE_ENV === 'development') {\n  await fetch('http://localhost:3000/api/process', {\n    method: 'POST',\n    body: JSON.stringify(data),\n  });\n} else {\n  await qstash.publishJSON({ url, body: data });\n}\n```\n\n# Option 3: Use Vercel preview URLs\nPreview deploys give you public URLs for testing\n\n### Using default retry behavior for all message types\n\nSeverity: MEDIUM\n\nSituation: Critical payment webhook uses defaults. 3 retries over minutes. Payment\nprocessor is temporarily down for 15 minutes. Message marked as failed.\nPayment reconciliation manual work required.\n\nSymptoms:\n- Critical messages marked failed\n- Manual intervention needed for retries\n- Temporary outages causing permanent failures\n\nWhy this breaks:\nDefault retry behavior (3 attempts, short backoff) works for many cases but\nnot all. Some endpoints need more attempts, longer backoff, or different\nstrategies. One size doesn't fit all.\n\nRecommended fix:\n\n# Configure retries per message:\n```typescript\n// Critical operations: more retries, longer backoff\nawait qstash.publishJSON({\n  url: 'https://myapp.com/api/payment-webhook',\n  body: { paymentId: '123' },\n  retries: 5,\n  // Backoff: 10s, 30s, 1m, 5m, 30m\n});\n\n// Non-critical notifications: fewer retries\nawait qstash.publishJSON({\n  url: 'https://myapp.com/api/analytics',\n  body: { event: 'pageview' },\n  retries: 1,  // Fail fast, not critical\n});\n```\n\n# Consider your endpoint's recovery time:\n- Database down: May need 5+ minutes\n- Third-party API: May need hours\n- Internal service: Usually quick\n\n# Use failure callbacks for dead letter handling:\n```typescript\nawait qstash.publishJSON({\n  url: 'https://myapp.com/api/critical',\n  body: data,\n  failureCallback: 'https://myapp.com/api/dead-letter',\n});\n```\n\n### Sending large payloads instead of references\n\nSeverity: MEDIUM\n\nSituation: Message contains entire document (5MB). QStash rejects - body too large.\nEven if accepted, slow to transmit. Expensive. Wastes bandwidth.\n\nSymptoms:\n- Message publish failures\n- Slow message delivery\n- High bandwidth costs\n\nWhy this breaks:\nQStash has message size limits (around 500KB body). Large payloads slow\ndelivery, increase costs, and can fail entirely. Messages should be\nlightweight triggers, not data carriers.\n\nRecommended fix:\n\n# Send references, not data:\n```typescript\n// BAD: Large payload\nawait qstash.publishJSON({\n  url: 'https://myapp.com/api/process',\n  body: { document: largeDocumentContent },  // 5MB!\n});\n\n// GOOD: Reference only\nawait qstash.publishJSON({\n  url: 'https://myapp.com/api/process',\n  body: { documentId: 'doc_123' },  // Fetch in handler\n});\n```\n\n# In your handler:\n```typescript\nexport async function POST(req: NextRequest) {\n  const { documentId } = await req.json();\n  const document = await storage.get(documentId);  // Fetch actual data\n  await processDocument(document);\n}\n```\n\n# Large data storage options:\n- S3/R2/Blob storage for files\n- Database for structured data\n- Redis for temporary data (Upstash Redis pairs well)\n\n### Not using callback/failureCallback for critical flows\n\nSeverity: MEDIUM\n\nSituation: Important task published. QStash delivers. Endpoint processes. But your\nsystem doesn't know it succeeded. User stuck waiting. No feedback loop.\n\nSymptoms:\n- No visibility into message delivery\n- Users waiting for actions that completed\n- No alerting on failures\n\nWhy this breaks:\nQStash is fire-and-forget by default. Without callbacks, you don't know\nif messages were delivered successfully. For critical flows, you need\nthe feedback loop to update state and handle failures.\n\nRecommended fix:\n\n# Use callbacks for critical operations:\n```typescript\nawait qstash.publishJSON({\n  url: 'https://myapp.com/api/send-email',\n  body: { userId: '123', template: 'welcome' },\n  callback: 'https://myapp.com/api/email-callback',\n  failureCallback: 'https://myapp.com/api/email-failed',\n});\n```\n\n# Handle the callback:\n```typescript\n// app/api/email-callback/route.ts\nexport async function POST(req: NextRequest) {\n  // Verify signature first!\n  const data = await req.json();\n\n  // data.sourceMessageId - original message\n  // data.status - HTTP status code\n  // data.body - response from endpoint\n\n  await db.emailLogs.update({\n    where: { messageId: data.sourceMessageId },\n    data: { status: 'delivered' },\n  });\n\n  return NextResponse.json({ received: true });\n}\n```\n\n# Failure callback for alerting:\n```typescript\n// app/api/email-failed/route.ts\nexport async function POST(req: NextRequest) {\n  const data = await req.json();\n  await alerting.notify(`Email failed: ${data.sourceMessageId}`);\n  await db.emailLogs.update({\n    where: { messageId: data.sourceMessageId },\n    data: { status: 'failed', error: data.body },\n  });\n}\n```\n\n### Cron schedules using wrong timezone\n\nSeverity: MEDIUM\n\nSituation: Scheduled daily report at \"9am\". But 9am in which timezone? QStash uses UTC.\nReport runs at 4am local time. Users confused. Support tickets filed.\n\nSymptoms:\n- Schedules running at unexpected times\n- Off-by-one-hour issues during DST\n- User complaints about report timing\n\nWhy this breaks:\nQStash cron schedules run in UTC. If you think in local time but configure\nin UTC, schedules will run at unexpected times. This is especially tricky\nwith daylight saving time changes.\n\nRecommended fix:\n\n# QStash uses UTC:\n```typescript\n// This runs at 9am UTC, not local time\nawait qstash.schedules.create({\n  destination: 'https://myapp.com/api/daily-report',\n  cron: '0 9 * * *',  // 9am UTC\n});\n```\n\n# Convert to UTC:\n- 9am EST = 2pm UTC (winter) / 1pm UTC (summer)\n- 9am PST = 5pm UTC (winter) / 4pm UTC (summer)\n\n# Document timezone in schedule name:\n```typescript\nawait qstash.schedules.create({\n  destination: 'https://myapp.com/api/daily-report',\n  cron: '0 14 * * *',  // 9am EST (14:00 UTC)\n  body: JSON.stringify({\n    timezone: 'America/New_York',\n    localTime: '9:00 AM',\n  }),\n});\n```\n\n# Handle DST programmatically if needed:\nUpdate schedules when DST changes, or accept UTC timing\n\n### URL groups with dead or outdated endpoints\n\nSeverity: MEDIUM\n\nSituation: URL group has 5 endpoints. One service deprecated months ago. Messages\nstill fan out to it. Failures in dashboard. Wasted attempts. Slower delivery.\n\nSymptoms:\n- Failed deliveries in URL groups\n- Messages to deprecated services\n- Slow fan-out due to timeouts\n\nWhy this breaks:\nURL groups persist until explicitly updated. When services change, endpoints\nbecome stale. QStash tries to deliver to dead URLs, wastes retries, and\nthe failure noise obscures real issues.\n\nRecommended fix:\n\n# Audit URL groups regularly:\n```typescript\nconst groups = await qstash.urlGroups.list();\nfor (const group of groups) {\n  console.log(`Group: ${group.name}`);\n  for (const endpoint of group.endpoints) {\n    // Check if endpoint is still valid\n    try {\n      await fetch(endpoint.url, { method: 'HEAD' });\n      console.log(`  OK: ${endpoint.url}`);\n    } catch {\n      console.log(`  DEAD: ${endpoint.url}`);\n    }\n  }\n}\n```\n\n# Update groups when services change:\n```typescript\n// Remove dead endpoint\nawait qstash.urlGroups.removeEndpoints({\n  name: 'order-processors',\n  endpoints: [{ url: 'https://old-service.myapp.com/api/process' }],\n});\n```\n\n# Automate in CI/CD:\nCheck URL group health as part of deployment\n\n## Validation Checks\n\n### Webhook signature verification\n\nSeverity: CRITICAL\n\nMessage: QStash webhook handlers must verify signatures using Receiver\n\nFix action: Add signature verification: const receiver = new Receiver({ currentSigningKey, nextSigningKey }); await receiver.verify({ signature, body, url })\n\n### Both signing keys configured\n\nSeverity: CRITICAL\n\nMessage: QStash Receiver must have both currentSigningKey and nextSigningKey for key rotation\n\nFix action: Configure both keys: new Receiver({ currentSigningKey: process.env.QSTASH_CURRENT_SIGNING_KEY, nextSigningKey: process.env.QSTASH_NEXT_SIGNING_KEY })\n\n### QStash token hardcoded\n\nSeverity: CRITICAL\n\nMessage: QStash token must not be hardcoded - use environment variables\n\nFix action: Use process.env.QSTASH_TOKEN\n\n### QStash signing keys hardcoded\n\nSeverity: CRITICAL\n\nMessage: QStash signing keys must not be hardcoded\n\nFix action: Use process.env.QSTASH_CURRENT_SIGNING_KEY and process.env.QSTASH_NEXT_SIGNING_KEY\n\n### Localhost URL in QStash publish\n\nSeverity: CRITICAL\n\nMessage: QStash cannot reach localhost - endpoints must be publicly accessible\n\nFix action: Use a public URL (e.g., your deployed domain or ngrok for testing)\n\n### HTTP URL instead of HTTPS\n\nSeverity: ERROR\n\nMessage: QStash requires HTTPS URLs for security\n\nFix action: Change http:// to https://\n\n### QStash publish without error handling\n\nSeverity: ERROR\n\nMessage: QStash publish calls should have error handling for rate limits and failures\n\nFix action: Wrap in try/catch and handle errors appropriately\n\n### Using parsed JSON for signature verification\n\nSeverity: CRITICAL\n\nMessage: Signature verification requires raw body (req.text()), not parsed JSON\n\nFix action: Use await req.text() to get raw body for verification\n\n### Callback endpoint without signature verification\n\nSeverity: CRITICAL\n\nMessage: Callback endpoints must also verify signatures - they receive QStash requests too\n\nFix action: Add Receiver signature verification to callback handlers\n\n### Schedule without destination URL\n\nSeverity: ERROR\n\nMessage: QStash schedules require a destination URL\n\nFix action: Add destination: 'https://your-app.com/api/endpoint' to schedule options\n\n## Collaboration\n\n### Delegation Triggers\n\n- complex workflow|multi-step|state machine -> inngest (Need durable step functions with checkpointing)\n- redis queue|worker process|job priority -> bullmq-specialist (Need traditional queue with workers)\n- ai background|long running ai|model inference -> trigger-dev (Need AI-specific background processing)\n- deploy|vercel|production|environment -> vercel-deployment (Need deployment configuration for QStash)\n- database|persistence|state|sync -> supabase-backend (Need database for job state)\n- auth|user context|session -> nextjs-supabase-auth (Need user context in message handlers)\n\n### Serverless Background Jobs\n\nSkills: upstash-qstash, nextjs-app-router, vercel-deployment\n\nWorkflow:\n\n```\n1. Define API route handlers (nextjs-app-router)\n2. Configure QStash integration (upstash-qstash)\n3. Deploy with environment vars (vercel-deployment)\n```\n\n### Reliable Webhooks\n\nSkills: upstash-qstash, stripe-integration, supabase-backend\n\nWorkflow:\n\n```\n1. Receive webhooks from Stripe (stripe-integration)\n2. Queue for reliable processing (upstash-qstash)\n3. Persist state to database (supabase-backend)\n```\n\n### Scheduled Reports\n\nSkills: upstash-qstash, email-systems, supabase-backend\n\nWorkflow:\n\n```\n1. Configure cron schedule (upstash-qstash)\n2. Query data for report (supabase-backend)\n3. Send via email system (email-systems)\n```\n\n### Fan-out Notifications\n\nSkills: upstash-qstash, email-systems, slack-bot-builder\n\nWorkflow:\n\n```\n1. Publish to URL group (upstash-qstash)\n2. Email handler receives (email-systems)\n3. Slack handler receives (slack-bot-builder)\n```\n\n### Gradual Migration to Workflows\n\nSkills: upstash-qstash, inngest\n\nWorkflow:\n\n```\n1. Start with simple QStash messages (upstash-qstash)\n2. Identify multi-step patterns\n3. Migrate complex flows to Inngest (inngest)\n4. Keep simple schedules in QStash\n```\n\n## Related Skills\n\nWorks well with: `vercel-deployment`, `nextjs-app-router`, `redis-specialist`, `email-systems`, `supabase-backend`, `cloudflare-workers`\n\n## When to Use\n- User mentions or implies: qstash\n- User mentions or implies: upstash queue\n- User mentions or implies: serverless cron\n- User mentions or implies: scheduled http\n- User mentions or implies: message queue serverless\n- User mentions or implies: vercel cron\n- User mentions or implies: delayed message\n\n## Limitations\n- Use this skill only when the task clearly matches the scope described above.\n- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.\n- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.","tags":["upstash","qstash","antigravity","awesome","skills","sickn33","agent-skills","agentic-skills","ai-agent-skills","ai-agents","ai-coding","ai-workflows"],"capabilities":["skill","source-sickn33","skill-upstash-qstash","topic-agent-skills","topic-agentic-skills","topic-ai-agent-skills","topic-ai-agents","topic-ai-coding","topic-ai-workflows","topic-antigravity","topic-antigravity-skills","topic-claude-code","topic-claude-code-skills","topic-codex-cli","topic-codex-skills"],"categories":["antigravity-awesome-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/sickn33/antigravity-awesome-skills/upstash-qstash","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add sickn33/antigravity-awesome-skills","source_repo":"https://github.com/sickn33/antigravity-awesome-skills","install_from":"skills.sh"}},"qualityScore":"0.700","qualityRationale":"deterministic score 0.70 from registry signals: · indexed on github topic:agent-skills · 34404 github stars · SKILL.md body (24,704 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-04-22T00:51:54.431Z","embedding":null,"createdAt":"2026-04-18T21:46:54.860Z","updatedAt":"2026-04-22T00:51:54.431Z","lastSeenAt":"2026-04-22T00:51:54.431Z","tsv":"'/api/analytics'',':1670 '/api/charge'',':675,1310 '/api/critical'',':1716 '/api/critical-task'',':502 '/api/cron/daily-report'',':328 '/api/daily-report'',':2156,2192 '/api/dead-letter'',':1722 '/api/email-callback'',':1975 '/api/email-failed'',':1979 '/api/endpoint''':2645 '/api/heavy-process'',':1042 '/api/notify'',':701,1334 '/api/payment-webhook'',':1647 '/api/process''':609,613,2366 '/api/process'',':243,1207,1805,1818 '/api/qstash-callback'',':509 '/api/qstash-failed'',':513 '/api/reminder'',':262 '/api/scheduled'',':279 '/api/send-email'',':1966 '/api/track''':617 '0':330,2158,2194 '00':2199,2207 '1':255,971,1484,1675,2749,2786,2823,2862,2895 '100':1196 '1000':286 '10s':1654 '123':246,265,678,685,1313,1650,1822,1969 '127.0.0.1':1476 '14':2195,2198 '15':1570 '1m':1656 '1pm':2170 '2':976,1498,2758,2794,2830,2870,2904 '200':551 '2pm':2167 '3':982,1531,1560,1602,2765,2802,2838,2877,2910 '30':893,928 '300':553 '3000':1489 '3000/api/process':1518 '30m':1658 '30s':1655 '4':2917 '401':445,853 '429':1090 '456':505,704,1337 '4am':2076 '4pm':2178 '5':1652,1690,2236 '500':1117,1145 '5000':680,1315 '500kb':1770 '5m':1657 '5mb':1736,1809 '5pm':2175 '60':267,268,1348 '789':635 '86400':287 '9':331,335,2159,2206 '9am':2064,2066,2146,2160,2165,2173,2196 'accept':726,1744,2220 'access':1440,1468,2507 'acknowledg':963 'action':247,1910,2395,2429,2461,2480,2509,2537,2561,2588,2618,2640 'actual':1846 'add':2396,2619,2641 'ago':2242 'ai':2680,2684,2692 'ai-specif':2691 'alert':1914,2024 'alerting.notify':2038 'alreadi':1372 'also':1365,2609 'altern':1026 'alway':58,381,425,792 'america/new_york':2204 'amount':679,1314 'analytics.myapp.com':616 'analytics.myapp.com/api/track''':615 'anoth':1013 'anyon':773 'api':1695,2751 'app':384,2743,2756,2933 'app/api/email-callback/route.ts':1984 'app/api/email-failed/route.ts':2026 'app/api/qstash-callback/route.ts':519 'app/api/webhook/route.ts':382 'application/json':346 'appropri':2568 'architect':155 'architectur':1454 'around':1769 'ask':3025 'async':220,410,521,818,966,985,1831,1986,2028 'attack':730 'attempt':1603,1617,2253 'audit':2306 'auth':2720,2727 'autom':2367 'aw':179 'await':238,257,274,323,356,361,423,430,453,497,531,554,599,627,670,696,831,838,990,997,1005,1037,1164,1180,1199,1305,1329,1515,1525,1642,1665,1711,1800,1813,1838,1842,1848,1961,1996,2009,2035,2037,2042,2151,2187,2313,2335,2356,2405,2590 'aws-lambda':178 'backend':2714,2784,2809,2821,2837,2943 'background':302,2681,2694,2735 'backoff':1605,1619,1641,1653 'bad':1797 'bandwidth':1750,1759 'base':27,694,1112,1325 'bash':1486 'basic':205 'batch':1189 'becom':865,2286 'begin':905 'behavior':1547,1601 'best':1301 'bodi':244,263,280,338,422,434,452,503,546,548,633,676,702,711,830,834,842,1043,1167,1186,1208,1311,1335,1344,1521,1528,1648,1671,1717,1739,1771,1806,1819,1967,2201,2408,2582,2595 'bot':2859,2883 'boundari':3033 'break':764,924,1107,1263,1426,1598,1763,1919,2105,2275 'builder':2860,2884 'built':76 'built-in':75 'bullmq':148,2673 'bullmq-specialist':147,2672 'burst':1068,1124 'busi':1303 'call':50,120,222,1509,2550 'callback':95,131,195,460,496,506,514,733,877,932,1705,1929,1956,1972,1982,2022,2598,2606,2624 'callback-handl':130 'callback-verif':194 'callback/failurecallback':1873 'cannot':2500 'capabl':113 'carrier':1789 'case':84,1609 'catch':1168,2343 'caus':1593 'chang':2136,2218,2284,2351,2538 'charg':683,1240,1249,1317 'charge-ord':682 'check':757,872,1140,1151,1156,1369,2328,2370,2379 'checkpoint':2665 'ci/cd':2369 'clarif':3027 'clear':3000 'client':224,230,307,313,484,490,585,591,653,659 'cloud':55,1432 'cloudflar':173,2945 'cloudflare-work':172,2944 'code':545,2004 'cold':1058 'collabor':2649 'complain':1137 'complaint':1258,2099 'complet':96,1373,1912 'complex':141,2652,2912 'complex-workflow':140 'configur':79,1458,1631,2119,2413,2430,2705,2759,2824 'confus':2080 'consid':942,1052,1680 'consol':169,1215 'console.log':347,2320,2340,2344 'const':227,310,321,354,395,415,421,428,449,487,529,588,656,803,823,829,836,988,1836,1840,1994,2033,2311,2316,2324,2399 'contain':534,1733 'content':344,693,1324 'content-bas':692,1323 'content-typ':343 'contentbaseddedupl':707,1340 'context':2722,2730 'convert':2162 'core':163 'corrupt':1246 'cost':1760,1777 'could':1000 'craftsman':161 'creat':317,349,595,951 'criteria':3036 'critic':481,649,723,1086,1224,1289,1296,1383,1555,1582,1636,1661,1679,1875,1940,1958,2384,2415,2449,2470,2497,2576,2604 'cron':72,123,290,329,2052,2107,2157,2193,2825,2966,2985 'current':401,809,866,2437,2483 'currentsigningkey':399,807,2403,2422,2435 'custom':665,1239,1299 'daili':282,341,2061 'dashboard':911,1152,1157,1213,1414,2251 'data':450,455,530,533,788,1007,1245,1523,1529,1718,1788,1795,1847,1852,1862,1866,1995,2014,2034,2047,2832 'data.body':2005,2051 'data.sourcemessageid':556,1998,2013,2041,2046 'data.status':550,552,2001 'databas':1686,1859,2708,2716,2806 'date.now':285 'day':91,333 'daylight':2133 'db.emaillogs.update':2010,2043 'db.jobs.create':1006 'dead':1707,2226,2293,2345,2354 'dedupl':105,129,639,663,668,695,1222,1270,1282,1294,1345,1357 'deduplicationid':681,1316 'default':1347,1545,1559,1599,1927 'defin':2750 'delay':85,134,189,252,266,1088,2990 'delay-schedul':133 'delayed-messag':188 'deleg':1048,2650 'delet':358 'deliv':212,469,1097,1884,1937,2016,2291 'deliveri':29,101,126,272,462,478,517,1757,1775,1906,2255,2258 'deploy':1390,1537,2377,2516,2696,2702,2704,2747,2766,2772,2930 'deprec':2240,2264 'describ':3004 'design':960 'destin':325,540,2153,2189,2628,2637,2642 'dev':2689 'develop':1385,1481,1501,1505,1514 'differ':1621 'direct':780,1510 'discov':731 'doc':1821 'document':1735,1807,1841,1850,2181 'documentid':1820,1837,1844 'doesn':936,1625,1890 'domain':2517 'doubl':108,903,1252 'double-process':107 'drop':1099 'dst':2097,2210,2217 'due':2270 'duplic':641,917,952,1248,1260 'durabl':2661 'e.g':2514 'edg':716,1054 'els':1524 'email':250,1242,1251,2039,2817,2841,2844,2855,2871,2875,2939 'email-system':2816,2843,2854,2874,2938 'endpoint':45,214,237,372,377,515,570,605,623,725,766,878,935,1367,1381,1614,1682,1885,2008,2229,2237,2285,2325,2330,2355,2362,2503,2599,2607 'endpoint.url':2337,2342,2346 'entir':1734,1781 'env':1513 'environ':2458,2699,2768,3016 'environment-specif':3015 'error':441,849,1091,1169,1188,2050,2528,2543,2546,2553,2567,2631 'error.message':1171 'especi':2130 'est':2166,2197 'even':1742 'event':151,154,583,636,1070,1256,1672 'event-architect':153 'event-sourc':150 'everi':332 'exhaust':1126 'expect':1376 'expens':1748 'expert':6,16,3021 'explicit':2280 'export':409,520,817,965,1830,1985,2027 'fail':104,471,901,914,944,1403,1411,1418,1473,1575,1585,1676,1780,2040,2049,2257 'failur':1265,1595,1704,1754,1916,1952,2021,2249,2299,2559 'failurecallback':510,1719,1976 'fake':735 'fan':564,2245,2268,2847 'fan-out':563,2267,2846 'fanout':193 'fast':962,975,981,987,1025,1677 'faster':1057 'feedback':1899,1945 'fetch':1516,1823,1845,2336 'fewer':1663 'file':1858,2083 'fire':66,1923 'fire-and-forget':65,1922 'first':528,974,1993 'fit':1627 'fix':791,959,1139,1292,1461,1630,1791,1954,2138,2305,2394,2428,2460,2479,2508,2536,2560,2587,2617,2639 'flood':737 'flow':1876,1941,2913 'forget':68,1925 'framework':170 'free':87,1115,1144 'function':177,183,411,522,819,967,1832,1987,2029,2663 'fundament':1453 'futur':94 'get':464,1084,2593 'give':1538 'go':1150 'good':1326,1810 'gradual':2885 'group':138,562,598,621,2224,2234,2261,2277,2308,2312,2317,2319,2321,2348,2372,2866 'group.endpoints':2327 'group.name':2322 'handl':70,132,1161,1709,1951,1980,2209,2544,2554,2566 'handler':751,888,950,1825,1828,2388,2625,2733,2753,2872,2879 'happen':1268,1407 'hardcod':2447,2456,2468,2478 'hash':709,1342 'head':2339 'header':342,756 'health':2373 'heavi':890,1018,1031 'hello':706 'hiccup':1230 'high':885,1066,1227,1758 'higher':1120,1154 'hit':1060,1078 'hour':256,1698,2094 'http':26,34,119,221,543,1471,1488,2002,2522,2972 'http-base':25 'https':41,1469,2526,2532 'id':112,538,666,714,1300,1320,1353 'idempot':647,1368 'identifi':2905 'implement':1158 'impli':2953,2958,2964,2970,2976,2983,2989 'import':223,306,386,390,483,584,652,748,799,1880 'includ':1172 'increas':1776 'individu':1197 'infer':2686 'infrastructur':32,305 'inngest':143,2659,2893,2915,2916 'input':3030 'instead':1004,1194,1422,1726,2524 'integr':2761,2781,2793 'interfac':37 'intern':1394,1443,1699 'internet':1439 'internet-access':1438 'intervent':1587 'invalid':442,850 'inventory.myapp.com':608 'inventory.myapp.com/api/process''':607 'ip':1444,1479 'issu':1459,2095,2303 'isvalid':429,438,837,846 'item':1203 'item.id':1210 'itemid':1209 'items.map':1202 'job':22,187,291,303,320,2670,2718,2736 'jobid':1044 'json':2571,2586 'json.parse':451 'json.stringify':339,1522,2202 'kafka':203 'keep':2918 'key':403,408,797,811,816,859,863,875,2412,2426,2432,2439,2444,2467,2474,2485,2490 'know':99,1134,1892,1933 'lambda':180 'larg':1724,1741,1772,1798,1851 'largedocumentcont':1808 'later':1179 'letter':1708 'lightweight':1785 'limit':1063,1077,1114,1123,1127,1143,1155,1160,1174,1219,1768,2557,2992 'list':351 'local':1176,1388,1416,1480,1500,2077,2116,2149 'localhost':1442,1475,1517,2491,2502 'localqueue.add':1181 'localtim':2205 'logic':1273,1364 'long':881,948,2682 'long-run':947 'longer':1618,1640 'loop':98,1900,1946 'machin':2658 'make':1366 'malici':740 'manag':31 'mani':1608 'manipul':789 'manual':1578,1586 'mark':898,913,1573,1584 'marktaskcomplet':555 'mass':1072 'match':3001 'math.floor':284 'may':1688,1696 'medium':1553,1730,1878,2058,2231 'mention':2951,2956,2962,2968,2974,2981,2987 'messag':9,19,111,116,128,190,206,209,235,368,380,467,482,537,567,626,638,642,705,736,784,899,912,921,953,980,989,999,1008,1015,1073,1079,1094,1190,1201,1236,1274,1297,1322,1350,1402,1409,1550,1572,1583,1634,1732,1752,1756,1766,1782,1905,1935,2000,2243,2262,2385,2416,2450,2471,2498,2529,2547,2577,2605,2632,2732,2900,2977,2991 'message-dedupl':127 'message.id':1045 'messageid':2012,2045 'messages/day':1118,1146 'method':1519,2338 'migrat':2886,2911 'minut':1563,1571,1691 'miss':752,3038 'mode':1502 'model':2685 'monitor':1130,1211 'month':2241 'multi':2655,2907 'multi-step':2654,2906 'multipl':569,579,1278 'must':46,870,1285,1465,2389,2419,2453,2475,2504,2608 'myapp.com':242,261,278,327,501,508,512,674,700,1041,1206,1309,1333,1646,1669,1715,1721,1804,1817,1965,1974,1978,2155,2191 'myapp.com/api/analytics'',':1668 'myapp.com/api/charge'',':673,1308 'myapp.com/api/critical'',':1714 'myapp.com/api/critical-task'',':500 'myapp.com/api/cron/daily-report'',':326 'myapp.com/api/daily-report'',':2154,2190 'myapp.com/api/dead-letter'',':1720 'myapp.com/api/email-callback'',':1973 'myapp.com/api/email-failed'',':1977 'myapp.com/api/heavy-process'',':1040 'myapp.com/api/notify'',':699,1332 'myapp.com/api/payment-webhook'',':1645 'myapp.com/api/process'',':241,1205,1803,1816 'myapp.com/api/qstash-callback'',':507 'myapp.com/api/qstash-failed'',':511 'myapp.com/api/reminder'',':260 'myapp.com/api/scheduled'',':277 'myapp.com/api/send-email'',':1964 'name':601,2185,2358 'need':218,300,475,576,1588,1615,1689,1697,1943,2213,2660,2675,2690,2703,2715,2728 'netlifi':182 'netlify-funct':181 'network':1229,1264,1447 'never':59 'new':229,312,397,489,590,658,805,2401,2433 'next':406,814,2442,2488 'next.js':383 'next/server':394 'nextj':171,2725,2742,2755,2932 'nextjs-app-rout':2741,2754,2931 'nextjs-supabase-auth':2724 'nextrequest':391,414,525,822,970,1835,1990,2032 'nextrespons':392 'nextresponse.json':440,457,558,848,1021,1047,2018 'nextsigningkey':404,812,864,2404,2424,2440 'ngrok':1487,1492,2519 'ngrok/localtunnel':1485 'nois':2300 'non':1660 'non-crit':1659 'notbefor':283 'notif':651,1085,1328,1662,2849 'notifi':465,578 'obscur':2301 'off-by-one-hour':2090 'ok':2341 'old-service.myapp.com':2365 'old-service.myapp.com/api/process''':2364 'one':1623,2093,2238 'oper':1225,1290,1304,1371,1637,1959 'option':1482,1483,1497,1530,1854,2648 'orchestr':158 'order':603,631,684,2360 'order-processor':602,630,2359 'order.placed':637 'orderid':634,677,1312,1318 'origin':536,1999 'outag':1592 'outdat':2228 'output':3010 'pageview':1673 'pair':1869 'pars':977,2570,2585 'parsemessag':991 'part':2375 'parti':1694 'path':781 'pattern':184,204,2909 'pay':1147 'payload':741,1725,1773,1799 'payment':650,1556,1564,1576 'paymentid':1649 'peak':1103 'pend':1010 'per':1633 'period':301 'perman':1594 'permiss':3031 'persist':2278,2709,2803 'plan':1111,1142,1358 'plan-bas':1110 'possibl':1192 'post':412,523,728,820,968,1520,1833,1988,2030 'potenti':787 'prevent':106,640 'preview':1534,1536 'principl':33 'prioriti':2671 'privat':1446,1478 'private/localhost':1380 'pro':1119,1153 'process':109,253,448,643,742,758,785,856,891,904,918,954,986,1101,1253,1375,1406,1886,2669,2695,2798 'process.env.node':1512 'process.env.qstash':232,315,400,405,492,593,661,808,813,2436,2441,2463,2482,2487 'processdocu':1849 'processheavywork':998 'processmessag':454 'processor':604,632,1565,2361 'product':1392,1420,1462,2698 'programmat':2211 'provid':1281 'pst':2174 'public':48,768,1437,1467,1540,2506,2512 'publish':207,494,618,1074,1198,1232,1753,1882,2495,2541,2549,2863 'qstash':3,5,13,15,44,49,69,115,165,228,311,367,379,488,589,657,719,765,860,895,910,925,941,1014,1028,1061,1075,1093,1108,1183,1280,1377,1396,1413,1427,1495,1499,1507,1737,1764,1883,1920,2070,2106,2139,2288,2386,2417,2445,2451,2465,2472,2494,2499,2530,2540,2548,2614,2633,2707,2740,2760,2764,2778,2801,2815,2829,2853,2869,2892,2899,2903,2922,2954 'qstash-messag':114 'qstash-retri':1182 'qstash-sdk':164 'qstash.batchjson':1200 'qstash.publishjson':239,258,275,498,628,671,697,1038,1165,1306,1330,1526,1643,1666,1712,1801,1814,1962 'qstash.schedules.create':324,2152,2188 'qstash.schedules.delete':362 'qstash.schedules.list':357 'qstash.urlgroups.addendpoints':600 'qstash.urlgroups.list':2314 'qstash.urlgroups.removeendpoints':2357 'queri':2831 'queu':1022 'queue':10,20,146,983,1175,2667,2677,2795,2960,2978 'quick':1128,1702 'rate':1062,1076,1113,1159,1173,2556 'raw':833,2581,2594 'reach':1379,1399,1436,2501 'real':2302 'receiv':378,387,396,398,516,559,624,747,800,804,806,1035,2019,2393,2400,2402,2418,2434,2613,2620,2787,2873,2880 'receiver.verify':431,839,2406 'recommend':790,958,1138,1291,1460,1629,1790,1953,2137,2304 'reconcili':1577 'recoveri':1684 'recur':294 'redi':145,200,1863,1868,2666,2936 'redis-queu':144 'redis-specialist':2935 'refer':1728,1793,1811 'regular':2309 'reject':1080,1738 'relat':197,2923 'reliabl':24,219,2773,2797 'remov':2353 'report':281,2062,2073,2101,2811,2834 'req':413,524,821,969,992,1834,1989,2031 'req.headers.get':417,825 'req.json':532,1839,1997,2036 'req.text':424,832,2583,2591 'req.url':436,844 'request':729,759,776,2615 'requir':835,1455,1463,1470,1580,2531,2580,2635,3029 'respond':883,938,1024 'respons':547,2006 'retri':73,902,916,946,957,1178,1184,1234,1267,1363,1546,1561,1590,1600,1632,1639,1651,1664,1674,2296 'return':439,456,557,847,1020,1046,2017 'review':3022 'rotat':861,868,876,2427 'rout':2752 'router':385,2744,2757,2934 'run':949,1428,2074,2086,2109,2124,2144,2683 'runtim':1055 's3/r2/blob':1855 'safe':446,854 'safeti':3032 'save':2134 'schedul':11,21,63,88,118,135,186,289,295,319,322,348,353,355,360,2053,2060,2085,2108,2122,2184,2215,2626,2634,2647,2810,2826,2920,2971 'schedule.scheduleid':350,363 'scheduled-http-cal':117 'scheduled-job':185 'scope':139,3003 'sdk':166,1233 'seamless':874 'second':89,269,894,929,1349 'secur':2535 'send':208,566,688,775,1723,1792,2839 'sent':1237,1243,1277 'server':1389 'serverless':8,18,122,2734,2965,2979 'serverless-cron':121 'servic':580,1700,2239,2265,2283,2350 'session':2723 'set':292 'sever':722,884,1065,1226,1382,1552,1729,1877,2057,2230,2383,2414,2448,2469,2496,2527,2545,2575,2603,2630 'sharp':715 'shipping.myapp.com':612 'shipping.myapp.com/api/process''':611 'short':1604 'show':1216,1410 'sign':402,407,810,815,862,2411,2438,2443,2466,2473,2484,2489 'signatur':57,364,369,416,420,427,432,433,443,527,721,755,771,794,824,828,840,841,851,973,1992,2381,2391,2397,2407,2573,2578,2601,2611,2621 'silent':1404 'simpl':234,2898,2919 'situat':724,886,1067,1228,1384,1554,1731,1879,2059,2232 'size':1624,1767 'skill':2737,2775,2812,2850,2889,2924,2995 'skill-upstash-qstash' 'skip':1506 'slack':2858,2878,2882 'slack-bot-build':2857,2881 'slow':1745,1755,1774,2266 'slower':2254 'sourc':152 'source-sickn33' 'sourcemessageid':535 'speak':40,43 'specialist':149,2674,2937 'specif':271,2693,3017 'stale':2287 'start':1059,2896 'state':1949,2657,2710,2719,2804 'status':444,463,479,518,542,544,852,1009,2003,2015,2048 'step':2656,2662,2908 'still':1122,2244,2332 'stop':3023 'storag':1853,1856 'storage.get':1843 'strategi':1622 'stripe':2780,2790,2792 'stripe-integr':2779,2791 'structur':1861 'stuck':1896 'substitut':3013 'succeed':102,1894 'success':458,1938,3035 'sudden':1098 'summer':2172,2180 'supabas':2713,2726,2783,2808,2820,2836,2942 'supabase-backend':2712,2782,2807,2819,2835,2941 'support':2081 'symptom':745,906,1089,1247,1408,1581,1751,1901,2084,2256 'sync':2711 'system':739,1889,2818,2842,2845,2856,2876,2940 'take':879,892 'task':28,296,1087,1881,2999 'taskid':504 'templat':1970 'tempor':160 'temporal-craftsman':159 'temporari':1591,1865 'temporarili':1567 'test':1496,1543,2521,3019 'think':2114 'third':1693 'third-parti':1692 'throw':1187 'ticket':2082 'tier':1116 'time':273,896,940,1104,1279,1685,2078,2089,2102,2117,2127,2135,2150,2222 'timeout':908,930,1001,2272 'timezon':2056,2069,2182,2203 'token':231,233,314,316,491,493,592,594,660,662,2446,2452,2464 'tomorrow':288 'tool':162 'topic-agent-skills' 'topic-agentic-skills' 'topic-ai-agent-skills' 'topic-ai-agents' 'topic-ai-coding' 'topic-ai-workflows' 'topic-antigravity' 'topic-antigravity-skills' 'topic-claude-code' 'topic-claude-code-skills' 'topic-codex-cli' 'topic-codex-skills' 'track':477 'tradit':2676 'transmit':1747 'treat':3008 'tri':1163,2289,2334 'tricki':2131 'trigger':1036,1071,1786,2651,2688 'trigger-dev':2687 'true':459,560,708,1023,1049,1341,2020 'trust':60,744 'try/catch':2564 'twice':1238,1241,1244 'two':858 'type':340,345,1338,1551 'typescript':798,964,1033,1162,1193,1298,1503,1635,1710,1796,1829,1960,1983,2025,2142,2186,2310,2352 'unauthor':783 'unexpect':1064,2088,2126 'unreach':1449 'unverifi':61 'updat':1948,2214,2281,2347 'upstash':2,4,12,14,168,199,202,419,754,827,1214,1430,1867,2739,2763,2777,2800,2814,2828,2852,2868,2891,2902,2959 'upstash-consol':167 'upstash-kafka':201 'upstash-qstash':1,2738,2762,2776,2799,2813,2827,2851,2867,2890,2901 'upstash-redi':198 'upstash-signatur':418,753,826 'upstash/qstash':226,309,389,486,587,655,802 'url':52,137,240,259,276,435,499,539,541,561,597,606,610,614,672,698,734,769,843,1039,1166,1185,1204,1307,1331,1395,1441,1464,1493,1527,1535,1541,1644,1667,1713,1802,1815,1963,2223,2233,2260,2276,2294,2307,2363,2371,2409,2492,2513,2523,2533,2629,2638,2865 'url-group':136 'urlgroup':629 'usag':1217 'use':83,110,217,299,375,474,575,646,712,1012,1027,1053,1221,1286,1293,1421,1490,1532,1544,1558,1703,1872,1955,2054,2071,2140,2392,2457,2462,2481,2510,2569,2589,2949,2993 'user':1081,1136,1257,1895,1907,2079,2098,2721,2729,2950,2955,2961,2967,2973,2980,2986 'userid':245,264,703,1336,1968 'usual':1701 'utc':337,2072,2111,2121,2141,2147,2161,2164,2168,2171,2176,2179,2200,2221 'valid':979,2333,2378,3018 'var':2769 'variabl':2459 'vercel':176,1051,1533,2697,2701,2746,2771,2929,2984 'vercel-deploy':2700,2745,2770,2928 'vercel-funct':175 'verif':196,365,761,772,2382,2398,2574,2579,2597,2602,2622 'verifi':56,366,426,526,718,793,972,1991,2390,2610 'via':2840 'visibl':1903 'wait':1897,1908 'wast':956,1749,2252,2295 'webhook':62,125,192,720,750,887,907,1034,1557,2380,2387,2774,2788 'webhook-deliveri':124 'webhook-fanout':191 'welcom':249,1339,1971 'welcome-email':248 'well':1870,2926 'window':669,691,1346,1355 'winter':2169,2177 'within':667,690 'without':30,304,770,1129,1269,1928,2542,2600,2627 'won':686,1132 'work':1019,1032,1386,1415,1579,1606,2925 'worker':174,2668,2679,2946 'workflow':142,157,2653,2748,2785,2822,2861,2888,2894 'workflow-orchestr':156 'wrap':2562 'wrong':2055 'your-app.com':2644 'your-app.com/api/endpoint''':2643","prices":[{"id":"d3ca9f70-2501-4600-858f-e84e408a7928","listingId":"90acf66f-e461-40e1-be68-e3815906be1b","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"sickn33","category":"antigravity-awesome-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T21:46:54.860Z"}],"sources":[{"listingId":"90acf66f-e461-40e1-be68-e3815906be1b","source":"github","sourceId":"sickn33/antigravity-awesome-skills/upstash-qstash","sourceUrl":"https://github.com/sickn33/antigravity-awesome-skills/tree/main/skills/upstash-qstash","isPrimary":false,"firstSeenAt":"2026-04-18T21:46:54.860Z","lastSeenAt":"2026-04-22T00:51:54.431Z"}],"details":{"listingId":"90acf66f-e461-40e1-be68-e3815906be1b","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"sickn33","slug":"upstash-qstash","github":{"repo":"sickn33/antigravity-awesome-skills","stars":34404,"topics":["agent-skills","agentic-skills","ai-agent-skills","ai-agents","ai-coding","ai-workflows","antigravity","antigravity-skills","claude-code","claude-code-skills","codex-cli","codex-skills","cursor","cursor-skills","developer-tools","gemini-cli","gemini-skills","kiro","mcp","skill-library"],"license":"mit","html_url":"https://github.com/sickn33/antigravity-awesome-skills","pushed_at":"2026-04-21T16:43:40Z","description":"Installable GitHub library of 1,400+ agentic skills for Claude Code, Cursor, Codex CLI, Gemini CLI, Antigravity, and more. Includes installer CLI, bundles, workflows, and official/community skill collections.","skill_md_sha":"d1f4d365c40a8c1b38a10267821a09eae2c7a21b","skill_md_path":"skills/upstash-qstash/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/sickn33/antigravity-awesome-skills/tree/main/skills/upstash-qstash"},"layout":"multi","source":"github","category":"antigravity-awesome-skills","frontmatter":{"name":"upstash-qstash","description":"Upstash QStash expert for serverless message queues, scheduled"},"skills_sh_url":"https://skills.sh/sickn33/antigravity-awesome-skills/upstash-qstash"},"updatedAt":"2026-04-22T00:51:54.431Z"}}