When choosing an application background-job platform, separate duplicate submission, retried execution and duplicate external effects. Trigger.dev, Inngest, Temporal Cloud, Hatchet and Windmill offer different units for durable work and retries. None of the documentation examined gives you permission to assume that an arbitrary external write becomes safe merely because the workflow engine records progress.
Our executed local reservation model makes that distinction visible: four requests committed four reservations with no deduplication or attempt-scoped keys, two with run-scoped keys, and one with a stable business-operation key. The model represents an external service accepting a write before its acknowledgement is lost. It is not a benchmark of the five platforms.
Compare the unit that retries
| Platform | Documented work boundary | Integration decision |
|---|---|---|
| Trigger.dev | Task triggers and retryable task runs | Trigger deduplication and external API idempotency need separate keys |
| Inngest | Durable steps with their own retries | Separate steps reduce repeated completed work; the uncertain write still needs protection |
| Temporal Cloud | Workflow orchestration and Activities | Keep external work in Activities and make repeatable effects explicit |
| Hatchet | Tasks with retry and timeout settings | Translate execution and scheduling timeouts separately; retain a business-operation identity |
| Windmill | Flow steps and configurable error handling | Review retry exhaustion and continue-on-error as separate business outcomes |
The ambiguous reservation we actually modeled
Consider reserving inventory for order 42. The external provider accepts the reservation, but the worker loses the response before saving success. The worker tries again. Later, a second workflow run processes the same intended reservation. We executed two attempts in each of two runs against a single-process, in-memory provider ledger.
A run-scoped key committed two reservations; a business-operation key committed one. With no key, all four requests created reservations. A different key for every attempt also created four. A stable key per run deduplicated attempts within each run but did not connect the two runs. A stable reserve-order-42-v1 key connected all four requests in this fixture.
The decisive point is where the deduplication happens. If the provider has committed but the workflow has not checkpointed, a completed-step cache cannot know the response that was lost. A local “done” flag written after the call has the same gap. A provider-side atomic deduplication contract, or a business-specific reconciliation protocol, is required at that boundary.
# Each strategy sees two runs and two attempts per run.
# The first acknowledgement in each run is lost after acceptance.
requests = 4
committed_reservations = {
"no key": 4,
"new key per attempt": 4,
"stable key per run": 2,
"stable key per business operation": 1,
}
This is not a universal instruction to use an order ID alone. A second legitimate reservation, a changed quantity or a new revision must not collide with the first operation. Our fixture fixes the payload and assumes the provider retains its deduplication record throughout both runs. Real retention periods, conflict behavior and read-after-write recovery need explicit design.
Trigger.dev
Trigger.dev’s idempotency guide explicitly separates deduplicating task triggers from making calls inside run() idempotent. It also distinguishes a run-stable identity from a business identity that can connect separate runs. This maps directly to the two-versus-one result in our local model.
It is a useful candidate when TypeScript task code and explicit parent-child task boundaries fit the application. Keep trigger keys, provider keys and operation revisions distinct. Moving an external write into a child task does not by itself resolve an acknowledgement lost after the provider accepted the write.
The Cloud plans combine plan allowances with execution-related charges and machine capacity. Do not assume a retry is commercially free because submission is deduplicated. We did not deploy a task or measure execution charges.
Inngest
Inngest documents durable step.run() operations and step retries. Completed step results can be reused, while failed steps retry independently. This can prevent later failures from repeating already recorded earlier work.
Split inventory reservation from a subsequent notification so that the notification’s failure does not unnecessarily repeat a completed reservation step. Still protect the reservation itself: our fault occurs before its successful result can be recorded. Durable step boundaries reduce the area of repeated work; they do not erase uncertainty inside the failed step.
This is a useful model for event-driven application functions that benefit from named step boundaries. The pricing page distinguishes executions, ingested events, concurrency and workers. Those are separate planning dimensions, not interchangeable units of one job.
Temporal Cloud
Temporal’s Activity documentation treats Activities as the place for work that interacts with the outside world and discusses idempotency. Workflow replay and Activity execution have different contracts. An external reservation belongs behind an Activity boundary with an appropriate retry and reconciliation design.
Temporal Cloud is worth evaluating when a team needs an explicit workflow model and can own the associated worker code and operational design. The tradeoff is that an application’s existing monolithic handler cannot simply be relabeled durable. Decide what is orchestration, what is an external effect, and which identity survives retries and separate business submissions.
Cloud billing uses Actions and storage, with support and other terms also relevant. An Action is not automatically equal to an Inngest execution or a Hatchet run. Our model does not estimate Cloud spend or test Temporal workers.
Hatchet
Hatchet’s current migration reference distinguishes task definitions, retries, non-retryable errors, execution timeouts and scheduling timeouts. That is useful for an application team whose unit of work is a directly invoked task. We use Temporal’s own documentation for Temporal claims rather than treating a competitor’s migration guide as independent verification.
The reservation model suggests an explicit migration review: preserve business-operation identity while changing task APIs, and distinguish a task waiting to start from one that started and might already have committed externally. A scheduling timeout and an execution timeout require different recovery questions.
Hatchet’s Cloud pricing separates runs, events, active storage and retention. Its free allowances do not establish that another provider’s similarly named unit is equivalent. We did not execute a Hatchet task or verify its hosted deduplication behavior.
Windmill
Windmill’s flow retry documentation allows step retries with fixed or exponential delays. It separately exposes continue-on-error behavior after retries are exhausted. That setting can be useful for an intentional exception branch, but can also allow a later notification to run after a reservation never succeeded.
For our inventory workflow, represent success, retryable uncertainty and a final business failure separately. Do not let a “job finished” notification imply that a reservation exists. This makes Windmill relevant when the team wants to compose scripts and flow steps, provided its error branches preserve the business meaning of the result.
The pricing page has Cloud and self-hosted configurations with distinct worker and seat considerations. Self-hosted software and managed execution are different scopes. We did not price infrastructure or run a Windmill flow.
Methodology and limitations
Toolverly Editorial checked the linked official documentation and pricing pages on October 18, 2026. Python 3.14.6 on macOS executed four identity strategies over the same four-request, fixed-payload trace. We retained every attempt, whether it committed a new reservation, the simulated acknowledgement loss, code and actual results. The model’s provider deduplication is atomic only inside this single-process fixture.
We did not run these five workflow platforms, create Cloud accounts, reserve inventory, send notifications or measure throughput, reliability or billing. Our comparison is a documentation-based integration analysis with a local fault model. AI assistance was used for research, scenario code and writing; outputs and consequential claims were reviewed before publication. Read about Toolverly Editorial.
Choose the platform whose work boundaries your team can express clearly, then prove the uncertain external-write boundary independently. For data-asset dependencies see our data orchestration comparison; for business teams connecting packaged apps see our workflow automation comparison. This article concerns developer-owned application jobs and their side effects.
Photo by Rob Wingate on Unsplash. Read about our publication or send a correction.
