Skip to content
Tech Stack14 June 2026 · 7 min readUpdated 30 September 2026

Background Job Architecture for SaaS: Inngest vs Trigger.dev vs Custom

Inngest, Trigger.dev, or Vercel Cron plus your own queue: how each handles retries, limits and cost for production SaaS, with vendor pricing checked on 30 September 2026.

Background Job Architecture for SaaS: Inngest vs Trigger.dev vs Custom

What you'll learn

  • Is Vercel Cron enough for background jobs in a SaaS?
  • Inngest vs Trigger.dev: which fits your SaaS job pattern?
  • When is a custom queue worth it?
Article contents

If you have ever written setTimeout(() => doExpensiveWork(), 0) in a Next.js API route, you made a bet. The request finishes, the connection closes, and the work either completes or disappears with no record of which one happened. The first action is to list your background jobs with three facts each: what triggers it, how long it can run, and what a silent failure costs you.

Every B2B SaaS ends up with this list: invoice generation, webhook retries, nightly aggregations, email sequences, PDF exports and AI enrichments that take too long for a user-facing request. The question is which layer owns them. Three credible paths exist for a serverless product: Inngest, Trigger.dev, or your own scheduler and queue. This post compares them using the vendors' own documentation, checked on 30 September 2026. Prices and limits change, so re-read the linked pages before you commit.

For the wider picture of jobs, webhooks, email and admin tooling, the SaaS backend infrastructure guide is the parent article, and Inngest for SaaS background jobs goes deeper on one option.

Is Vercel Cron enough for background jobs in a SaaS?

Vercel Cron is a scheduler, not a job system: it calls one of your routes on a schedule, does not retry an invocation that fails, and can occasionally deliver the same run twice.

An isometric 3D illustration of a mechanical clock mounted on a data conduit, emitting a single output arrow that dissolves into particles against a dark navy void

Vercel's documentation says cron delivery is best effort: a transient network error can prevent a request from reaching your function, in which case no runtime log exists for that run. It recommends designing jobs to be idempotent and reconciliation-based, so each run reprocesses everything outstanding since the last success, and using a lock when runs could overlap. Cron expressions are always in UTC.

The plan limits matter for the choice. According to Vercel's cron usage and pricing page, Hobby allows cron jobs once per day with per-hour precision (a 0 1 * * * job can fire anywhere between 1:00 and 1:59), while Pro allows once per minute with per-minute precision. Every plan allows 100 cron jobs per project. Cron jobs run as Vercel Functions, so function duration limits apply: a default of 300 seconds on every plan, a maximum of 800 seconds on Pro and Enterprise, and a 30-minute extended maximum in beta. If you remember a 60-second Pro cap from older guides, it no longer matches the current documentation.

A cron route is fine for a daily digest over a small dataset. It is the wrong tool when you need retries, per-job failure alerts, replay or work that fans out per customer. Vercel itself points to its Workflow and Queues products for durable work, which is a third option to evaluate if you already deploy there.

Inngest vs Trigger.dev: which fits your SaaS job pattern?

Inngest fits event-triggered, multi-step workflows because it memoizes each completed step, while Trigger.dev fits long-running tasks because its runs have no timeout and re-execute the whole run function when they retry.

How does Inngest handle retries and cost?

An isometric 3D scene of a staircase structure with glowing cyan checkpoint rings on each step and a single amber-glowing step in the middle, representing step-level retry isolation

Picture a five-step job that fails on step 4. Inngest's execution docs explain that the function is re-executed with the stored results of earlier steps injected, so completed steps are not run again and only the failed step repeats. The idempotency burden shrinks to the step that failed: an insert step should be an upsert, and an email step needs a sent guard.

Billing follows the same model. Inngest's pricing page defines an execution as a function run or a step execution, and states that a function with 5 step.run() calls uses 6 executions. Consider a hypothetical product running 10,000 jobs a month with 4 steps each: that is 10,000 x (1 + 4) = 50,000 executions, exactly the Free plan quota, and Free pauses execution when the quota is hit. At 100,000 such jobs you would use 500,000 executions, inside the 1M included with Pro. The exact overage rates are tiered, from $0.000050 down to $0.000015 per execution, so model your own step counts rather than trusting the headline price.

When does Trigger.dev win?

An isometric 3D industrial engineering corridor with a large data pipeline tube extending beyond the visible frame, its open terminus glowing cyan to suggest unlimited task runtime

Trigger.dev's pricing FAQ says tasks can run for as long as you need, with no timeouts, on every plan. That removes the need to chop a video transcode or a long crawl into timeout-safe pieces. The cost is on the retry side: its retry docs say a failed attempt runs the whole run function again, and suggest splitting work into smaller tasks that retry independently. Every database write in such a task therefore needs to be an upsert, and every external call needs an idempotency key.

Which one offers the control you need?

Both projects describe themselves as self-hostable, so a self-hosting requirement does not rule either out by itself. Inngest's self-hosting docs describe a single binary that defaults to SQLite and an in-memory Redis with snapshots, which suits single-node use; multi-node needs external PostgreSQL and Redis, and support is not guaranteed for self-hosted instances. Trigger.dev says it is open source and has a self-hosting guide. Read both before you answer a buyer's security questionnaire, and see the SaaS security and compliance guide for the compliance side of that conversation.

FreePaid tiers (verified 30 Sep 2026)History or log retention
Inngest$0, 50k executions, 5 concurrent stepsPro from $99/mo, 1M executions, 100+ concurrent steps; Business from $499/mo, 10M executions, 50024 hours Free, 7 days Pro, 14 days Business
Trigger.dev$0, $5 credits, 20 concurrent runsHobby $10/mo, 50 runs; Pro $50/mo, 200+ runs1 day Free, 7 days Hobby, 30 days Pro

Observability follows those numbers. Retention is the practical difference: on the Free tiers you can only look back about a day, so a failure that happened over a weekend may already be gone by Monday. If your on-call person needs to replay last week's failure, price the retention you need as well as the execution quota.

When is a custom queue worth it?

A custom queue is worth it when you already run persistent infrastructure and need behaviour that a hosted platform prices or limits awkwardly, because you then own retries, monitoring and recovery yourself.

What does BullMQ on Redis require?

BullMQ is an MIT-licensed Node.js library that builds a queue on Redis. Its documentation lists retries, repeatable cron-style jobs, per-worker concurrency and recovery from process crashes, and has a section on stalled jobs. It has no per-run fee, but you take on the operations work:

  1. A persistent Redis instance, not an ephemeral one.
  2. Worker processes with tuned concurrency and graceful shutdown.
  3. Stalled-job handling, so a crashed worker does not strand a job.
  4. A dashboard and alerting you choose or build.
  5. A policy for jobs that fail repeatedly.

On a purely serverless host you also need a long-lived worker somewhere else, which is another service to deploy and monitor. I am deliberately not giving a job-count break-even here: it depends on your step counts, your Redis cost and your time, and I have no primary source for a universal number. For the Redis side, see Redis, Upstash and Dragonfly for SaaS caching.

What does a custom setup look like in a real project?

Callidus, the React + Firebase + Stripe Connect clinic SaaS I built solo, runs its subscription lifecycle on scheduled Cloud Functions. Per its case study, a coordinator function runs daily at 09:00 UTC and fans out one Cloud Task per trialing tenant, following a 3-day email, 1-day email, expiry with 3-day grace, then suspension sequence, and a second scheduled function at 09:30 UTC escalates tenants with failed payments. The case study lists 15 cron jobs in total. That is a custom scheduler-plus-queue design on the Firebase stack, and it shows the pattern: a scheduler finds the work, a queue fans it out, and each task is small enough to retry alone.

How do you pick without overthinking it?

Pick the lowest-overhead option that covers today's volume, and choose the one whose failure mode you can live with.

  • Vercel Cron for a handful of idempotent scheduled jobs where a missed or duplicate run is tolerable.
  • Inngest when jobs are event-triggered with several steps and you want step-level retries.
  • Trigger.dev when tasks run long, need heavy runtimes, or you want an open-source platform.
  • BullMQ or cloud-native queues when you already operate the infrastructure and want flat, predictable costs.

The best SaaS MVP stack defers infrastructure cost until it is a real constraint, and background jobs are a classic case. If you use Supabase Edge Functions as a cron trigger layer, you get function logs and little else, so plan your own alerting.

Which of your jobs would hurt most if it silently failed tonight? Start with that one, and write down its retry and idempotency rules before choosing a tool.

Free resource

Free SaaS MVP Scope Template

A Notion document with the full feature checklist, MVP vs. nice-to-have table, pre-build questions, and cost signals — so you walk into any developer call knowing exactly what to ask for.

Get the template →
DL

Dusko Licanin

Full-Stack Developer · Banja Luka, Bosnia

Full-stack developer shipping SaaS MVPs, web apps, and mobile apps using AI-augmented workflows — without agency coordination overhead. Live portfolio: BookBed, Callidus, Pizzeria Bestek.

Frequently Asked Questions

How does Inngest compare to Trigger.dev for SaaS background jobs?

Inngest suits event-triggered, multi-step workflows, while Trigger.dev suits long-running tasks. Inngest's documentation says a retried function is re-executed with the stored results of earlier steps injected, so only the failed step repeats. Trigger.dev's retry documentation says a failed attempt runs the whole run function again, so its tasks need idempotent writes. On cost, Inngest meters a function run plus each step as executions, while Trigger.dev bills compute usage against plan credits. Check both pricing pages before you commit, because plans and limits change.

What is a SaaS job queue and when do you need one?

A job queue is a persistent store of work items that your application processes asynchronously, with retries, failure handling and visibility outside a user-facing request. You need one when work takes longer than an acceptable response time, when failures must retry automatically, or when you need to control concurrency. Typical triggers are webhook processing, invoice generation, email batches, exports and AI enrichment. A scheduler such as Vercel Cron only calls a route on a timetable; its documentation says failed invocations are not retried and delivery is best effort.

What is durable execution in SaaS applications?

Durable execution means a function survives failures and restarts by resuming from saved progress instead of vanishing or starting over. It matters most in multi-step workflows where a failure on step 4 should not force steps 1 to 3 to run again. Inngest implements it by memoizing each completed step and replaying stored results on retry. Trigger.dev takes a different route: its tasks have no timeouts on any plan, so a long task can run to completion. Both reduce defensive code, but you still need idempotent side effects in the parts that can re-run.

What are background workers in SaaS and how do they work?

Background workers are processes or functions that execute jobs outside the web request, so slow or failure-prone work does not block a response. A worker picks up a job, runs it and marks it complete or retries it on failure. In serverless setups that can be an Inngest function triggered by an event, a Trigger.dev task called from your code, or a BullMQ worker on a persistent host connected to Redis. The shared design rule is idempotency: a job must produce the same result whether it runs once or several times.

When should I use BullMQ instead of Inngest or Trigger.dev?

Use BullMQ when you already operate persistent infrastructure and want a library under your own control rather than a hosted platform. BullMQ is an MIT-licensed Node.js library built on Redis, and its documentation covers retries, repeatable jobs, concurrency and stalled-job recovery. The price of that control is operations: you run Redis and the workers, and you choose or build the dashboard and alerting. I do not know of a primary source for a universal job-count break-even, so model your own step counts and Redis cost before deciding.