Skip to content

Temporal Workflows with Go: a roadmap ​

Why this matters, in 30 seconds ​

Real business processes are long and fragile. A signup charges a card, sends emails, waits 14 days for a trial to end, then converts the account. An order waits for a courier, a payment, a human. Without Temporal you glue this together with cron jobs, queues, status columns, retry loops and "stuck order" dashboards, and every crash leaves something half done.

A Workflow is ordinary Go code that describes the whole process, including the waiting. Temporal records every step in an Event History. If a Worker crashes, another Worker replays the code against that history and continues exactly where it stopped, even if the stop happened 13 days into a 14-day sleep. You write the process as a function. Temporal makes it durable.

The price: Workflow code must be deterministic, and you must change it carefully once executions are running. Most of this roadmap is about using that power without breaking that rule.


The roadmap ​

Read in order. Each stage builds on the previous one.

Stage 1: Foundations (core concepts, must-know) ​

#ChapterYou'll be able to…
01What is a Workflow?Explain the problem Workflows solve, Definition vs Type vs Execution, the Workflow/Activity split and the vocabulary. Run a first end-to-end program.
02Defining Workflows in GoWrite Workflow functions with the right signature, inputs and results, name and register them, and use the Go replacements for time, go, chan, select and maps.

Stage 2: How Workflows really run (core concepts, the mental model) ​

#ChapterYou'll be able to…
03Determinism, Event History & ReplayRead an Event History, explain Commands vs Events and replay, spot non-deterministic code, use Side Effects, and write a replay test.
04Workflow Execution: lifecycle, IDs & limitsPick Workflow IDs, use the ID Reuse and Conflict policies, read statuses, set timeouts carefully, and know the history limits.
05Timers, Selectors & concurrencySleep for days, race a Timer against an Activity, fan out and pick the first result, and wait on conditions with workflow.Await.

Stage 3: Talking to and composing Workflows (daily use) ​

#ChapterYou'll be able to…
06Message passing: Queries, Signals & UpdatesTurn a Workflow into a stateful service: read it with Queries, steer it with Signals and Updates, use Signal-With-Start and Update-With-Start, and write safe handlers.
07Child WorkflowsSplit big processes into Child Workflows, choose a Parent Close Policy, and start fire-and-forget children correctly.

Stage 4: Controlling executions over time (operations & long-running) ​

#ChapterYou'll be able to…
08Cancel, Terminate, Pause & ResetChoose between the four controls, write cancellation-aware Workflows that clean up, and know what each control guarantees.
09Continue-As-NewRun entity Workflows forever by checkpointing state into a fresh run before the history gets too big.
10Schedules, Start Delay & Cron JobsRun Workflows on a clock with Schedules (overlap, catch-up, backfill, pause), delay a one-off start, and recognise legacy Cron Jobs.

Stage 5: Evolving and extending (advanced) ​

#ChapterYou'll be able to…
11Versioning: Worker Versioning & PatchingShip changes to Workflow code without breaking running executions, with workflow.GetVersion or Worker Versioning.
12Dynamic WorkflowsHandle Workflow Types that aren't known at compile time.
13Workflow Streams (Public Preview)Stream progress events and LLM tokens from a Workflow to UIs in real time.

Core concepts vs. implementation details ​

Core concepts: understand these firstImplementation details, options & sub-features: learn when needed
Workflow Definition, Type and Execution (01)Custom Workflow Type names, starting by name (02)
Workflow vs Activity: orchestration vs side effects (01)workflow.Go, channels, WaitGroup, DeterministicKeys (02)
Event History, Commands, Events, Replay (03)SideEffect, MutableSideEffect, IsReplaying, replay tests (03)
Determinism (03)Go runtime non-determinism checks (03, 11)
Workflow ID vs Run ID, statuses (04)ID Reuse / Conflict policies, Memo, Workflow timeouts & retries, limits (04)
Durable Timers (05)Selectors, soft timeouts, pick-first, AwaitWithTimeout (05)
Messages: Query, Signal, Update (06)Validators, Signal/Update-With-Start, Mutex, AllHandlersFinished (06)
Cancellation vs Termination (08)Disconnected cleanup contexts, Pause, Reset (08)
Continue-As-New and the Execution Chain (09)Suggested-CAN reasons, draining Signals, test hooks (09)
Versioning strategy (11)GetVersion lifecycle, cutover, Worker Versioning config (11)
—Child Workflows (07), Schedules & Cron (10), Dynamic Workflows (12), Workflow Streams (13)

Which tool do I need? ​

text
I need to…
├── run a multi-step process that must survive crashes            → a Workflow            → 01, 02
├── call an API / DB / LLM from it                                → an Activity           → Activities guide
├── wait (minutes … years)                                        → workflow.Sleep / Timer → 05
├── wait for whichever happens first (event, timeout, result)     → Selector / AwaitWithTimeout → 05
├── read its state from outside                                   → Query                 → 06
├── push an event into it, fire-and-forget                        → Signal                → 06
├── change it and get an answer / a rejection back                → Update (+ validator)  → 06
├── create-or-reach "the one execution for this business key"     → Workflow ID + Signal/Update-With-Start → 04, 06
├── split a huge process or delegate to another team's service    → Child Workflow        → 07
├── stop it                                                       → Cancel (cleanup) or Terminate (force) → 08
├── hold it during an incident                                    → Pause (Pre-release)   → 08
├── keep it alive forever (an entity)                             → Continue-As-New       → 09
├── start it every day / hour / Monday                            → Schedule              → 10
├── start it once, later                                          → Start Delay           → 10
├── change its code while executions are running                  → Worker Versioning or GetVersion → 11
└── show live progress in a UI                                    → Workflow Streams (Preview) or Queries → 13, 06

Go API cheat sheet ​

I want to…Go APIChapter
Define a Workflowfunc ProcessThing(ctx workflow.Context, in ThingInput) (ThingResult, error)02
Register itw.RegisterWorkflow(fn), w.RegisterWorkflowWithOptions(fn, workflow.RegisterOptions{Name: …})02
Start itc.ExecuteWorkflow(ctx, client.StartWorkflowOptions{ID, TaskQueue, …}, fn, in) → run.Get(ctx, &out)01, 04
Get back to itc.GetWorkflow(ctx, id, runID), c.DescribeWorkflow(ctx, id, runID)04
Read time, log, sleepworkflow.Now(ctx), workflow.GetLogger(ctx), workflow.Sleep(ctx, d)02, 05
Run things concurrentlyworkflow.Go, workflow.NewChannel, workflow.NewWaitGroup, workflow.NewSelector02, 05
Iterate a mapfor _, k := range workflow.DeterministicKeys(m)02
Record a non-deterministic valueworkflow.SideEffect, workflow.MutableSideEffect03
Test replay safetyworker.NewWorkflowReplayer() + ReplayWorkflowHistoryFromJSONFile03, 11
Control duplicatesWorkflowIDReusePolicy, WorkflowIDConflictPolicy, WorkflowExecutionErrorWhenAlreadyStarted04
Durable timer / raceworkflow.NewTimer, selector.AddFuture, workflow.AwaitWithTimeout05
Handle messagesworkflow.SetQueryHandler, workflow.GetSignalChannel, workflow.SetUpdateHandlerWithOptions06
Send messagesc.QueryWorkflow, c.SignalWorkflow, c.SignalWithStartWorkflow, c.UpdateWorkflow, c.UpdateWithStartWorkflow06
Wait for handlersworkflow.Await(ctx, func() bool { return workflow.AllHandlersFinished(ctx) })06, 09
Start a childworkflow.ExecuteChildWorkflow(workflow.WithChildOptions(ctx, opts), fn, in)07
Clean up on canceldefer + workflow.NewDisconnectedContext(ctx)08
Cancel / terminatec.CancelWorkflow, c.TerminateWorkflow (and …WithOptions for a reason)08
Checkpoint into a new runreturn workflow.NewContinueAsNewError(ctx, fn, nextInput), GetInfo(ctx).GetContinueAsNewSuggested()09
Run on a schedulec.ScheduleClient().Create(ctx, client.ScheduleOptions{ID, Spec, Action, …})10
Start later, onceclient.StartWorkflowOptions{StartDelay: d}10
Patch running codeworkflow.GetVersion(ctx, "change-id", workflow.DefaultVersion, 1)11
Catch unknown Workflow Typesw.RegisterDynamicWorkflow(fn, workflow.DynamicRegisterOptions{})12
Stream progressworkflowstreams.NewWorkflowStream, Topic(…).Publish, NewClient(…).Subscribe13

About the code samples ​

  • Each chapter is a self-contained module named github.com/acme/shop. Every Go block starts with // file: <path> so you can paste it into that path. Short ❌ fragments without that header are anti-patterns shown on purpose and aren't meant to compile.
  • All samples were compiled and go vet-checked against Go SDK v1.50.0 (go.temporal.io/sdk) and, for chapter 13, go.temporal.io/sdk/contrib/workflowstreams v0.1.1.
  • External systems (payment providers, couriers, email, LLMs) are interfaces or fakes. Swap in your real clients.
  • Run everything locally with temporal server start-dev (UI at http://localhost:8233).

Notes from checking the docs against the SDK ​

  • Already-started errors. The Encyclopedia says the default Conflict Policy (Fail) returns a "Workflow execution already started" error. The Go client in SDK v1.50.0 doesn't: unless you set WorkflowExecutionErrorWhenAlreadyStarted: true, ExecuteWorkflow returns a WorkflowRun for the existing run with a nil error. This also happens when the Reuse Policy rejects the start. See chapter 04.
  • workflow.RequestCancelWorkflow() appears in the Go Versioning page's runtime-check list. It doesn't exist. The real function is workflow.RequestCancelExternalWorkflow() (03, 11).
  • Dynamic handlers. The Dynamic Handler page lists Go among the SDKs with dynamic Workflows, Activities, Signals and Queries. SDK v1.50.0 has dynamic Workflows and Activities only. It has no dynamic Signal, Query or Update handler API (12).
  • Pausing from Go. Workflow Pause is Pre-release. The Go client has no Pause method, but the gRPC PauseWorkflowExecution / UnpauseWorkflowExecution calls exist through c.WorkflowService() (08).
  • GetVersion and patched(). The Encyclopedia's patched() walkthrough targets Python, .NET and Ruby. Go's GetVersion behaves the same way on replay without a marker: it keeps returning DefaultVersion for that change ID (11).
  • Not in the Go docs pages, but in the SDK:
    • GetInfo(ctx).GetContinueAsNewSuggestedReasons() tells you why Continue-As-New is suggested.
    • NewContinueAsNewErrorWithOptions exists.
    • DynamicRegisterOptions.LoadDynamicRuntimeOptions exists.
    • workflow.DeterministicKeys gives you sorted map keys.

Sources ​

Encyclopedia: Workflows · Workflow Definition · Workflow Execution · Workflow Id and Run Id · Events and Event History · Continue-As-New · Limits · Timers and Start Delay · Cancellation and Termination · Workflow Pause · Dynamic Handler · Schedule · Cron Job · Patching

Go SDK: Basics · Child Workflows · Continue-As-New · Cancellation · Timeouts · Message passing · Schedules · Timers · Selectors · Side Effects · Dynamic Workflow · Versioning · Workflow Streams