Yashveer Singh
Connect
<- All posts
SaaS Architecture and Scaling12 min read

Workflow Engines: When You Need Temporal, When You Need Cron

A workflow engine runs multi step processes that have state, branching logic, and the need to survive failures and restarts. Cron schedules recurring single tasks. A job queue runs discrete background work. The three tools overlap in marketing but not in design. Choosing a workflow engine for a cron job is over-engineering. Choosing a cron job for a multi-step business process is a reliability disaster.

Written by Yashveer Singh, founder of Yashveer Labs.

What you actually need to know

  • Cron is for simple recurring tasks with no cross-run state.
  • A job queue is for discrete background work that runs once per trigger.
  • A workflow engine is for multi-step processes with state, branching, and durable execution.
  • The three tools are not interchangeable. Using the wrong one makes the right problem much harder.
  • Most early stage SaaS products need cron and a job queue. A workflow engine is earned, not assumed.
ToolBest fitState managementStep level retriesObservability
Cron (native, Cloud Scheduler)Scheduled single tasksNoneNoMinimal
Job queue (Postgres, BullMQ)Discrete triggered workNoneAt job levelGood
InngestMulti-step managed workflowsDurableYes, per stepBuilt in dashboard
Trigger.devMulti-step managed workflowsDurableYes, per stepBuilt in dashboard
Temporal CloudComplex durable workflowsDurableYes, per stepWeb UI, full history
AWS Step FunctionsAWS-native workflowsDurableYes, per stepCloudWatch

The core argument

Cron, a job queue, and a workflow engine are presented in similar marketing language. "Run background work." "Schedule tasks." "Handle async processes." The vocabulary overlaps enough that many teams pick the first option that sounds right and spend months paying for that choice.

The distinction is simpler than the marketing suggests. Cron schedules recurring work. A queue runs work triggered by events. A workflow engine runs work that has steps, state, and the need to survive failures without starting over. Each tool does one thing well. None of them does all three.

The team that runs a subscription renewal check on a cron job is making the right choice. The team that runs a user onboarding flow on a cron job with a dozen database flags tracking which step each user is on has invented a broken workflow engine. I have inherited several of those. They break in different ways at every scale. The state tracking is always incomplete. The failure handling is always wrong. The observability is usually zero.

The team that reaches for Temporal on day one for sending welcome emails has the opposite problem. Temporal is a serious piece of infrastructure. It is the right tool for the right problem. Sending a single email is not that problem.

The practical question is where to draw the line. The answer I use: if the process has three or more sequential steps with different failure modes, if any step can wait on an external event, or if you need to know the state of an in-flight process at any given moment, reach for a workflow engine. Otherwise, a queue is sufficient.

The three tools, concretely

Cron

Cron is correct for: nightly report generation, subscription trial expiry checks, cache cleanup, scheduled data sync from a third party, anything that runs on a schedule and starts fresh each time.

The failure model is simple. If the job fails, it either retries or it does not, depending on the scheduler. The next run starts fresh. There is no state to recover. Managed cron options like Cloud Scheduler, Render Cron Jobs, and in-queue schedulers all work well. The operational overhead is minimal.

Job queue

A queue is correct for: welcome email on sign up, file processing after upload, webhook delivery, report generation triggered by user action, third party API calls, anything that runs once in response to an event.

The failure model is retry with exponential backoff and dead letter handling. Each job is independent. A failed job does not affect other jobs. The queue has no concept of steps or state between jobs. If you find yourself using a queue job to set a database flag that the next queue job checks, you are building a poor version of a workflow engine.

Workflow engine

A workflow engine is correct for: user onboarding that spans multiple days, payment reconciliation across multiple systems, provisioning flows that call multiple APIs in sequence, document processing pipelines with human review steps, anything that has steps and needs to know where it is.

The engine persists the workflow state after each step. A worker crash does not lose the workflow. The workflow resumes from the last successful step. Each step has its own retry policy. The engine can pause the workflow until an external event arrives, such as a user clicking a confirmation link or a payment completing.

What it costs

OptionSetup timeMonthly cost at moderate scaleOperational overhead
Native cron (in existing scheduler)HoursNegligibleMinimal
Cloud Scheduler (GCP)Half a dayUnder 5 USDMinimal
Job queue (already have Postgres)Half a dayNegligibleNegligible
InngestOne dayFree to 250 USDMinimal, managed
Trigger.devOne dayFree to 250 USDMinimal, managed
Temporal CloudTwo to three days25 USD per million actionsMedium
Self-hosted TemporalOne to two weeksInfrastructure costHigh

Features to look for

  • Durable state persistence. Workflow state survives worker restarts.
  • Per-step retry policies with configurable backoff.
  • Workflow visibility. You can see every in-flight workflow, its current step, and its history.
  • Event-driven step triggers. A workflow can pause and wait for an external signal.
  • Cancellation and termination. You can stop a workflow in progress.
  • Versioning. You can deploy new workflow code without breaking in-flight workflows.
  • Local development support. You can run the workflow engine in development without a production dependency.

Expert opinion

I have watched teams reach for Temporal when they needed a queue, and reach for cron when they needed a workflow engine. The first group spent their initial sprint learning an infrastructure tool instead of shipping product. The second group spent the next year maintaining a state machine built out of database flags and job logic. Both mistakes are expensive. The workflow engine conversation should start when the team has a concrete problem that cron and queues cannot solve cleanly. Before that point, it is a solution looking for a problem.

>

Yashveer Singh, founder of Yashveer Labs

How this played out on a real project

A SaaS client had a user onboarding flow that took three to five business days to complete. It involved provisioning a resource, waiting for a third party API to confirm provisioning, sending a series of guided setup emails at specific intervals, and notifying the sales team at the end. The flow was implemented as four cron jobs, each checking a status column on the user record.

The status column had twelve possible values by the time I saw the codebase. Five of them were dead states that users could reach but never escape from without manual intervention. The sales team had a spreadsheet for tracking users stuck in dead states. There were consistently thirty to fifty of them at any given time.

We migrated the flow to Inngest over two weeks. The workflow is readable code with named steps. Each step has its own retry policy. The Inngest dashboard shows every in-flight onboarding, its current step, and any failures. The dead states are gone because the workflow handles the failure cases explicitly. The sales team spreadsheet is gone.

The migration was two weeks of work that eliminated a class of recurring support burden. The codebase is smaller. The behavior is more predictable. For related infrastructure, background job queues the architecture decision founders skip covers the queue layer this sits on top of, and why your saas should have a job queue from day one covers the simpler adjacent tool.

Common mistakes

  1. Using a cron job with database flags to simulate a workflow. It breaks in every direction and is impossible to debug.
  2. Reaching for Temporal before having a concrete multi-step process problem. The operational overhead is real.
  3. No visibility into in-flight workflows. When something goes wrong, you have no way to inspect the state.
  4. Workflow code that cannot handle retries. The engine will retry steps. The code has to be safe to run more than once.
  5. No versioning strategy. Deploying new workflow code while old workflows are in flight causes state mismatches.
  6. Using a workflow engine for simple scheduled tasks. Cron is correct for that. The engine adds cost and complexity with no benefit.
  7. One retry policy for all steps. A step that calls a third party API needs different backoff than a step that writes to your database.

A four week plan

  1. Week one. Audit existing cron jobs and background work. Identify any that have grown into multi-step processes. Map the steps explicitly.
  2. Week two. For the identified multi-step processes, pick a workflow engine. For teams on Next.js or serverless, Inngest or Trigger.dev. For teams with more complex needs, evaluate Temporal Cloud.
  3. Week three. Migrate one multi-step process to the workflow engine. Run the old and new implementations in parallel. Compare outputs.
  4. Week four. Cut over. Migrate remaining candidates. Document which work belongs in cron, which belongs in the queue, and which belongs in the workflow engine. New processes follow the map.

For deeper reading on the job layer below workflows, background jobs at scale Inngest Trigger Cron and beyond covers the managed options in detail.

FAQ

Frequently asked

Author

The engineering bet behind Yashveer Labs

The bet I am running with Yashveer Labs is simple. Most software is built by people who treat it as a job. I treat it as a craft. Yashveer Singh, founder. Five production systems on the board so far. The arc points at machine learning, AI engineering, and cybersecurity. If your project is in any of those orbits, you are reading the right page.

Related reading