Strait Docs
Guides

Move your workflows from Temporal to Strait.

Migrating from Temporal

This guide helps you migrate from Temporal to Strait. While both handle workflow orchestration, Strait takes a simpler, HTTP-first approach.

Concept Mapping

TemporalStraitNotes
WorkflowWorkflowDAG of steps with dependencies
ActivityJobHTTP endpoint that does the work
Workflow ExecutionWorkflow RunA single execution of a workflow
Activity ExecutionRunA single execution of a job step
Task QueueJob queuePostgreSQL-backed, no external broker
WorkerWorker modeBuilt into the Strait binary
SignalEvent TriggerPause and wait for external events
Timersleep step / delayed_secsBuilt into workflow steps
Child WorkflowSub-workflowNested workflow execution
Retry Policyretry_strategyexponential, linear, fixed
Search AttributesJob metadataQueryable via API

Key Differences

  1. No SDK lock-in -- Temporal requires language-specific SDKs for workflows and activities. Strait uses HTTP endpoints -- your job logic can be in any language or framework.

  2. Simpler deployment -- Temporal requires a cluster (server + database + Elasticsearch). Strait is a single binary with PostgreSQL.

  3. Declarative workflows -- Temporal workflows are imperative code. Strait workflows are declarative JSON DAGs with step conditions and template variables.

  4. No replay/determinism constraints -- Temporal replays workflow history, requiring deterministic code. Strait steps are independent HTTP calls with no replay semantics.

Migration Steps

1. Convert Activities to Jobs

Temporal Activity:

func SendEmail(ctx context.Context, to string, subject string) error {
    return emailClient.Send(to, subject)
}

Strait Job: Create the job definition, then implement the HTTP endpoint:

strait jobs create --name "send-email" \
  --endpoint "https://your-app.com/api/jobs/send-email"

2. Convert Workflows to DAGs

Temporal Workflow:

func OrderWorkflow(ctx workflow.Context, order Order) error {
    err := workflow.ExecuteActivity(ctx, ValidateOrder, order).Get(ctx, nil)
    err = workflow.ExecuteActivity(ctx, ChargePayment, order).Get(ctx, nil)
    err = workflow.ExecuteActivity(ctx, FulfillOrder, order).Get(ctx, nil)
    return err
}

Strait Workflow:

{
  "name": "order-workflow",
  "steps": [
    { "name": "validate", "job": "validate-order" },
    { "name": "charge", "job": "charge-payment", "depends_on": ["validate"] },
    { "name": "fulfill", "job": "fulfill-order", "depends_on": ["charge"] }
  ]
}

3. Convert Signals to Event Triggers

Temporal:

ch := workflow.GetSignalChannel(ctx, "approval")
ch.Receive(ctx, &approved)

Strait: Use an approval step or event trigger:

{
  "name": "review",
  "type": "approval",
  "depends_on": ["analyze"],
  "timeout_secs": 86400
}

4. Replace Timers with Sleep Steps

Temporal:

workflow.Sleep(ctx, 24*time.Hour)

Strait:

{
  "name": "wait",
  "type": "sleep",
  "config": { "duration_secs": 86400 },
  "depends_on": ["notify"]
}

What You Gain

  • Simpler operations -- Single binary, no cluster management
  • Language-agnostic -- HTTP endpoints instead of SDK-specific workers
  • Built-in cost tracking -- Budget controls for AI workloads
  • Real-time CDC -- Stream changes to your app via PostgreSQL WAL
Was this page helpful?

On this page