| name | versioning-guide |
| description | This skill should be used when the user asks about "workflow versioning", "GetVersion", "workflow migration", "update running workflow", "workflow reset", "deploy workflow changes", "backward compatible workflow", or needs guidance on safely updating Temporal workflows. |
| version | 1.0.0 |
Temporal Workflow Versioning
Guidance for safely updating workflows while maintaining compatibility with running executions.
Why Versioning Matters
Temporal replays workflow history to reconstruct state. If workflow code changes, replay may fail with non-determinism errors. Versioning ensures:
- Running workflows complete successfully
- New workflows use updated logic
- Safe rollback if issues occur
GetVersion API
The primary tool for workflow versioning.
Basic Usage
func MyWorkflow(ctx workflow.Context, input Input) error {
v := workflow.GetVersion(ctx, "change-id", workflow.DefaultVersion, 1)
if v == workflow.DefaultVersion {
err := oldBehavior(ctx)
} else {
err := newBehavior(ctx)
}
return err
}
Parameters
| Parameter | Description |
|---|
ctx | Workflow context |
changeID | Unique identifier for this change point |
minSupported | Minimum version to support (usually DefaultVersion) |
maxSupported | Current version number |
Version Numbers
workflow.DefaultVersion (-1): Original code before any versioning
1, 2, 3, ...: Incremental version numbers
Common Scenarios
Adding New Activity
func OrderWorkflow(ctx workflow.Context, order Order) error {
err := workflow.ExecuteActivity(ctx, ValidateOrder, order).Get(ctx, nil)
if err != nil {
return err
}
v := workflow.GetVersion(ctx, "add-fraud-check", workflow.DefaultVersion, 1)
if v >= 1 {
err = workflow.ExecuteActivity(ctx, CheckFraud, order).Get(ctx, nil)
if err != nil {
return err
}
}
err = workflow.ExecuteActivity(ctx, ProcessPayment, order).Get(ctx, nil)
return err
}
Removing Activity
func OrderWorkflow(ctx workflow.Context, order Order) error {
v := workflow.GetVersion(ctx, "remove-legacy-check", workflow.DefaultVersion, 1)
if v == workflow.DefaultVersion {
workflow.ExecuteActivity(ctx, LegacyCheck, order).Get(ctx, nil)
}
return workflow.ExecuteActivity(ctx, ProcessOrder, order).Get(ctx, nil)
}
Changing Activity Parameters
func OrderWorkflow(ctx workflow.Context, order Order) error {
v := workflow.GetVersion(ctx, "new-shipping-params", workflow.DefaultVersion, 1)
var shippingResult ShippingResult
if v == workflow.DefaultVersion {
err := workflow.ExecuteActivity(ctx, ShipOrder, order.ID).Get(ctx, &shippingResult)
} else {
input := ShippingInput{
OrderID: order.ID,
Priority: order.Priority,
Address: order.ShippingAddress,
}
err := workflow.ExecuteActivity(ctx, ShipOrderV2, input).Get(ctx, &shippingResult)
}
return err
}
Multiple Versions
func OrderWorkflow(ctx workflow.Context, order Order) error {
v := workflow.GetVersion(ctx, "payment-flow", workflow.DefaultVersion, 2)
switch v {
case workflow.DefaultVersion:
return processPaymentV1(ctx, order)
case 1:
return processPaymentV2(ctx, order)
default:
return processPaymentV3(ctx, order)
}
}
Deployment Strategy
Safe Deployment Process
- Add version gates before deployment
- Deploy workers with new code
- Monitor for non-determinism errors
- Let old workflows complete naturally
- Clean up version gates after all old workflows finish
Deployment Timeline
Day 0: Deploy code with GetVersion
- New workflows: use new logic
- Old workflows: use old logic
Day 1-N: Old workflows complete naturally
Monitor for issues
Day N+1: Once all old workflows done:
- Remove version gates
- Simplify to new logic only
Monitoring During Rollout
# Watch for non-determinism errors
sum(rate(temporal_workflow_task_execution_failed_total{failure_reason="NonDeterminismError"}[5m]))
# Track workflow completions by version
# (requires custom search attributes)
Workflow Reset
Alternative to versioning for fixing stuck workflows.
When to Use Reset
- Workflow stuck due to bug
- Need to retry from specific point
- Cannot wait for natural completion
Reset Commands
temporal workflow reset \
--workflow-id <id> \
--event-id 10 \
--reason "Reset after bug fix"
temporal workflow reset \
--workflow-id <id> \
--type LastWorkflowTask \
--reason "Retry last decision"
temporal workflow reset \
--workflow-id <id> \
--type FirstWorkflowTask \
--reason "Start over"
temporal workflow reset-batch \
--query "WorkflowType='OrderWorkflow' AND ExecutionStatus='Running'" \
--type LastWorkflowTask \
--reason "Batch reset for bug fix"
Reset Types
| Type | Description | Use Case |
|---|
FirstWorkflowTask | Restart from beginning | Complete redo |
LastWorkflowTask | Redo last decision | Recent bug |
--event-id N | Reset to specific event | Targeted retry |
Best Practices
Version Gate Naming
Use descriptive, unique change IDs:
workflow.GetVersion(ctx, "add-fraud-check-2024-01", ...)
workflow.GetVersion(ctx, "payment-retry-logic", ...)
workflow.GetVersion(ctx, "shipping-v2-params", ...)
workflow.GetVersion(ctx, "change1", ...)
workflow.GetVersion(ctx, "fix", ...)
Cleanup Strategy
After all old workflows complete:
func OrderWorkflow(ctx workflow.Context, order Order) error {
v := workflow.GetVersion(ctx, "add-validation", workflow.DefaultVersion, 1)
if v >= 1 {
validate(ctx, order)
}
return process(ctx, order)
}
func OrderWorkflow(ctx workflow.Context, order Order) error {
validate(ctx, order)
return process(ctx, order)
}
Testing Versions
Test both old and new paths:
func TestOrderWorkflow_NewVersion(t *testing.T) {
env := s.NewTestWorkflowEnvironment()
env.ExecuteWorkflow(OrderWorkflow, testOrder)
}
func TestOrderWorkflow_ReplayOldHistory(t *testing.T) {
replayer := worker.NewWorkflowReplayer()
replayer.RegisterWorkflow(OrderWorkflow)
err := replayer.ReplayWorkflowHistoryFromJSONFile(nil, "old_history.json")
require.NoError(t, err)
}
Anti-Patterns
Don't Change Version IDs
workflow.GetVersion(ctx, "my-change", ...)
workflow.GetVersion(ctx, "my-change-v2", ...)
workflow.GetVersion(ctx, "my-change", DefaultVersion, 1)
workflow.GetVersion(ctx, "my-change", DefaultVersion, 2)
Don't Lower maxSupported
workflow.GetVersion(ctx, "change", DefaultVersion, 2)
workflow.GetVersion(ctx, "change", DefaultVersion, 1)
workflow.GetVersion(ctx, "change", DefaultVersion, 3)
Additional Resources
Reference Files
For detailed versioning patterns, consult:
references/version-patterns.md - Advanced versioning scenarios
references/migration-guide.md - Large-scale migration strategies