Temporal Workflow Determinism Rules
Intermediate
Enforce deterministic workflow code in Temporal — no I/O in workflows, no random values, no current time access, no threading, and proper use of Temporal's deterministic APIs.
File Patterns
**/workflows/****/workflow.ts**/workflow.go
This rule applies to files matching the patterns above.
Rule Content
rule-content.md
# Temporal Workflow Determinism Rules
## Rule
All Temporal workflow functions MUST be deterministic. No I/O, no randomness, no system time, no threading in workflow code. Use activities for all non-deterministic operations.
## Format
Workflow code produces the same result when replayed from event history. Any non-deterministic operation breaks replay.
## Requirements
### 1. No I/O in Workflow Code
```typescript
// BAD: HTTP call in workflow (non-deterministic)
export async function myWorkflow() {
const data = await fetch("https://api.example.com/data"); // BREAKS REPLAY
}
// GOOD: I/O in an activity
export async function myWorkflow() {
const data = await fetchData("https://api.example.com/data"); // Activity call
}
```
### 2. No Random Values in Workflow Code
```typescript
// BAD: Non-deterministic random
export async function myWorkflow() {
const id = Math.random().toString(36); // Different on replay!
const uuid = crypto.randomUUID(); // Different on replay!
}
// GOOD: Use Temporal's deterministic UUID
import { uuid4 } from "@temporalio/workflow";
export async function myWorkflow() {
const id = uuid4(); // Deterministic across replays
}
```
### 3. No Current Time in Workflow Code
```typescript
// BAD: System time changes on replay
export async function myWorkflow() {
const now = new Date(); // Different on replay!
const ts = Date.now(); // Different on replay!
}
// GOOD: Temporal workflow time (deterministic)
import { sleep } from "@temporalio/workflow";
export async function myWorkflow() {
// Use sleep for time-based logic
await sleep("5m");
// If you need current time, pass it via activity or signal
}
```
### 4. No Mutation of External State
```typescript
// BAD: Global state mutation
let counter = 0;
export async function myWorkflow() {
counter++; // Shared state, non-deterministic with multiple workflows
}
// GOOD: Local workflow state only
export async function myWorkflow() {
let counter = 0; // Local to this workflow instance
counter++;
}
```
### 5. Use getVersion for Workflow Code Changes
```typescript
import { patched } from "@temporalio/workflow";
export async function myWorkflow(order: Order) {
if (patched("add-validation-step")) {
// New code path (new workflow executions)
await validateOrder(order);
}
// Original code path (existing workflow executions continue here)
await processOrder(order);
}
```
## Anti-Patterns
- fetch(), axios, fs calls in workflow code
- Math.random() or crypto.randomUUID() in workflows
- new Date() or Date.now() in workflows
- Global/shared mutable state between workflow instances
- Changing workflow code without versioning (breaks running instances)
## Enforcement
Use Temporal's replay testing to verify determinism. Add determinism checks to code review checklist for all workflow code changes.FAQ
Discussion
Loading comments...