Temporal is a durable execution platform for long-running, stateful workflows. Instead of writing a DAG, you write ordinary code - a workflow function - and Temporal guarantees it runs to completion exactly as written even across process crashes, deploys, and machine failures that span seconds or months. It does this by persisting every step's result to an event history and replaying that history to reconstruct workflow state. For data and backend engineers, it solves the problem of orchestrating multi-step processes with retries, timeouts, and human-in-the-loop waits without hand-rolling a state machine in a database.

Workflows and activities

Code splits into two kinds. A workflow is deterministic orchestration logic - it must produce the same decisions when replayed, so it can't do I/O directly. An activity is the side-effecting work (an API call, a DB write, a file move) that Temporal retries independently with configurable policies. The workflow calls activities and awaits their results; Temporal records each result so a replay skips completed work.

@workflow.defn
class OrderWorkflow:
    @workflow.run
    async def run(self, order_id: str) -> str:
        await workflow.execute_activity(
            charge_card, order_id,
            start_to_close_timeout=timedelta(seconds=30),
            retry_policy=RetryPolicy(maximum_attempts=5))
        # durable timer — survives restarts, no polling loop
        await asyncio.sleep(timedelta(days=3).total_seconds())
        await workflow.execute_activity(send_followup, order_id,
            start_to_close_timeout=timedelta(seconds=30))
        return "done"

That three-day sleep is a durable timer, not a held thread - the worker can be redeployed a dozen times in between and the workflow resumes precisely where it left off.

Determinism and event history

Temporal's guarantee rests on replay: the server stores an append-only event history per workflow execution, and a worker reconstructs state by replaying it. That's why workflow code must be deterministic - no random, no direct clock reads, no nondeterministic iteration - and why side effects belong in activities. Changing workflow code that's already running requires versioning (the patched API) so in-flight executions don't break replay.

ConceptRole
WorkflowDeterministic orchestration code, replayed from history
ActivitySide-effecting unit, retried independently with policies
WorkerYour process that polls task queues and runs workflow/activity code
Event historyAppend-only log per execution that drives replay

Architecture and operation

The Temporal Server (a cluster of services plus a persistence store - Cassandra, PostgreSQL, or MySQL) handles scheduling, timers, and history; it never runs your code. Your workers, written in Go, Java, Python, TypeScript, or .NET, poll task queues and execute the actual logic, so you scale workers independently of the server. Temporal Cloud offers the server as a managed service. Signals deliver external input to a running workflow, and queries read its current state without mutating it.

Frequently asked questions

Is Temporal a replacement for Airflow? They overlap but differ in shape. Airflow is batch, schedule-driven data pipelines; Temporal is durable application workflows - order processing, provisioning, sagas - where each execution is long-lived and stateful. Many shops run both.

Why must workflow code be deterministic? Because Temporal recreates workflow state by replaying its event history. Nondeterministic operations would diverge on replay, so they're confined to activities, which are recorded rather than replayed.

How does it handle a worker crash mid-workflow? The event history is on the server. A new worker picks up the workflow, replays history to the last recorded point, and continues - no work already completed is repeated.

What languages are supported? Official SDKs for Go, Java, Python, TypeScript, and .NET, all talking to the same server and able to share a workflow across languages via task queues.