SimpleQ vs Upstash QStash
SimpleQ and Upstash QStash are both managed queues that publish over HTTP and deliver to your endpoint with retries, backoff, and a dead-letter queue — so if you're weighing QStash, the question that matters is what happens when a downstream rate-limits you. SimpleQ treats a 429, 503, or 529 as backpressure: the job defers and redelivers after Retry-After with no attempt burned, so it can ride out a sustained rate limit and still complete without spending its retry budget. QStash, by contrast, counts each retry as another billed message. SimpleQ also adds a three-signal ack protocol (ack/nack/defer) that cleanly separates success, failure, and backpressure. QStash is a mature, broad product with cron schedules, fan-out, and strict FIFO that SimpleQ doesn't have yet; but for AI and API-heavy backends whose reliability hinges on how rate limits are handled, SimpleQ is built for exactly that workload.
| Feature | SimpleQ | QStash |
|---|---|---|
| Managed | Yes | Yes |
| Delivery model | Push to the queue's webhook — configured once on the queue | Push to a per-message destination URL (or a URL Group) |
| Retries | Configurable backoff (exponential/fixed), set per queue | Configurable retries + backoff, set per message |
| Ack / completion signal | Three-signal protocol — ack (success), nack (failure + retryable flag), defer (backpressure). Return 200 fast, report the real outcome out-of-band. | HTTP response only (connection held up to 15 min free / 2 hr paid) or callbacks. No out-of-band ack/nack/defer. |
| Backpressure | 429/503/529 auto-defers with Retry-After relay — no attempt burned. A job can ride out 100 consecutive 429s and still complete. | Flow Control throttles parallelism; a Retry-After triggers a retry, which is a billed attempt. |
| Dead-letter queue | Built-in, single + bulk replay (API + dashboard) | Built-in DLQ + event logs |
| Idempotency / dedup | Publish-boundary idempotency key | Deduplication-Id or content-based dedup (default 15-min window) |
| Recurring schedules (cron) | Not yet — one-shot delay only | Yes — CRON expressions |
| Fan-out to many endpoints | No — one webhook per queue | Yes — URL Groups deliver one message to many endpoints |
| Strict FIFO / ordered delivery | Not offered | Yes — ordered Queues with parallelism control |
| Batch publish | Not yet | Yes — /v2/batch |
| Max delay | Up to 24h | Up to 7 days (free) / 1 year (paid) |
| Long-running handler | Ack mode — 200 in 15s, report later via ack/nack/defer | Hold the HTTP response up to 15 min (free) / 2 hr (paid) |
| LLM handling | Queue templates (anthropic / openai) preconfigure the queue; your code calls the model | Can call the provider directly (api: { name: "llm" }) with callbacks |
| Webhook signing | HMAC-SHA256, per-queue secret — a leaked secret affects one queue, not the org | Signing keys (JWT) with Receiver.verify + framework wrappers |
| SDKs | TypeScript (+ REST) | TypeScript, Python, and more |
| Maturity / compliance | Early access | GA; SOC-2 / SLA available via the Prod Pack add-on |
When to choose SimpleQ
- Your downstream returns 429 and you're tired of paying for it. QStash bills every retry as another message — a rate-limited job costs more the worse the downstream behaves. SimpleQ defers instead:
deferholds the job and redelivers afterRetry-Afterwith no attempt burned, so backpressure never spends your retry budget. - You want a downstream's bad day to stay contained. When a downstream is rate-limiting you, SimpleQ holds the job with
deferand redelivers onRetry-After— so a sustained 429 doesn't burn through your retry budget or cascade into failures. - Your handler outlives a synchronous HTTP response — LLM calls, video, slow third-party APIs. Ack mode returns 200 immediately and reports the real outcome later through three distinct callbacks: success, failure (with a retryable flag), or backpressure.
- You want jobs to fail loudly and replay easily. Built-in DLQ with single and bulk replay via API and dashboard, plus a full per-attempt audit trail (status, error, HTTP code, timestamp).
- You want one POST to stand up a production-ready AI queue.
template: "anthropic"or"openai"sets ack mode, timeout, and backoff tuned for that provider. - You want per-queue blast radius on secrets. HMAC signing secrets are per-queue, so a leak affects one queue, not the org.
When to choose QStash
- You need recurring schedules. QStash has cron; SimpleQ has one-shot delay up to 24h only.
- You need fan-out to multiple endpoints from one publish — QStash URL Groups. SimpleQ is one webhook per queue.
- You need strict FIFO ordering — QStash ordered Queues. SimpleQ doesn't guarantee ordering.
- You need batch publishing (
/v2/batch) or delays beyond 24h (QStash goes to 1 year). - You want QStash to call an LLM provider for you with callbacks, rather than your code making the call.
- You need a non-TypeScript SDK today (Python, etc.) or a GA product with SOC-2 / an uptime SLA — QStash has these now; SimpleQ is early access with a TS SDK.
- You're already on Upstash and want one vendor across Redis/Vector/QStash.
Coming from QStash?
- The publish model flips from per-message to per-queue. In QStash the destination URL goes in the publish path. In SimpleQ you
POST /v1/queuesonce with awebhookUrl(plusmaxAttempts,backoffType,rateLimitMax, etc.), then publish jobs to the queue name. Retry/rate config lives on the queue, not on each message. - Auth switches from QStash signing keys (
Receiver.verify) to SimpleQ HMAC-SHA256 with a per-queue secret (verify with@simpleq/sdk's webhook verifier). - Completion gets explicit. Where QStash relies on the HTTP status (or a held connection / callback), SimpleQ adds ack mode: 200 to acknowledge receipt, then
/ack,/nack, or/deferfor the real outcome. - Note the gaps: if you rely on cron, URL-group fan-out, FIFO, or batch on QStash, those aren't 1:1 in SimpleQ today.
QStash details verified June 2026.