.do
Data Storage

state

State machine foundation for durable workflow execution with automatic persistence

state

State machines as the foundation for durable workflow execution - enabling complex multi-step processes with automatic state persistence, transitions, and error recovery.

Overview

The state primitive is the foundational state machine that powers durable workflow execution. Every workflow (see workflows) is fundamentally a state machine that transitions through well-defined states as it executes.

Core Principle: Workflows ARE Code Functions (see functions) with state machines that enable:

  1. State Persistence - Automatic state storage between steps
  2. State Transitions - Well-defined progression through workflow stages
  3. Error Recovery - Resume from last successful state after failures
  4. Long-Running - Maintain state for hours, days, or weeks

This makes state machines the foundational primitive for orchestrating complex business processes that require durability and reliability.

State Machine Fundamentals

Finite State Machines (FSM)

Workflows are finite state machines with well-defined states and transitions:

import { workflow, state } from 'sdk.do'

// Order processing state machine
workflow('process-order', async ({ order }) => {
  // State: PENDING → VALIDATED
  const validated = await state.transition('PENDING', 'VALIDATED', async () => {
    await validateOrder(order)
    return { orderId: order.id, valid: true }
  })

  // State: VALIDATED → PAYMENT_PROCESSING
  const payment = await state.transition('VALIDATED', 'PAYMENT_PROCESSING', async () => {
    return await processPayment(order)
  })

  // State: PAYMENT_PROCESSING → PAYMENT_COMPLETED
  await state.transition('PAYMENT_PROCESSING', 'PAYMENT_COMPLETED', async () => {
    await confirmPayment(payment)
  })

  // State: PAYMENT_COMPLETED → SHIPPED
  await state.transition('PAYMENT_COMPLETED', 'SHIPPED', async () => {
    await createShipment(order)
  })

  // Final state: COMPLETED
  await state.transition('SHIPPED', 'COMPLETED', async () => {
    await sendConfirmation(order)
  })
})

State Transitions

State transitions define valid progressions through workflow stages:

import { state, workflow } from 'sdk.do'

// Define state machine
const orderStateMachine = state.machine({
  initial: 'PENDING',
  states: {
    PENDING: {
      on: {
        VALIDATE: 'VALIDATING',
      },
    },
    VALIDATING: {
      on: {
        SUCCESS: 'VALIDATED',
        FAILURE: 'VALIDATION_FAILED',
      },
    },
    VALIDATED: {
      on: {
        PROCESS_PAYMENT: 'PROCESSING_PAYMENT',
      },
    },
    PROCESSING_PAYMENT: {
      on: {
        SUCCESS: 'PAYMENT_COMPLETED',
        FAILURE: 'PAYMENT_FAILED',
      },
    },
    PAYMENT_COMPLETED: {
      on: {
        SHIP: 'SHIPPING',
      },
    },
    SHIPPING: {
      on: {
        SUCCESS: 'COMPLETED',
        FAILURE: 'SHIPPING_FAILED',
      },
    },
    COMPLETED: {
      type: 'final',
    },
    VALIDATION_FAILED: {
      type: 'final',
    },
    PAYMENT_FAILED: {
      on: {
        RETRY: 'PROCESSING_PAYMENT',
      },
    },
    SHIPPING_FAILED: {
      on: {
        RETRY: 'SHIPPING',
      },
    },
  },
})

// Use in workflow
workflow('process-order', async ({ order }) => {
  const machine = await orderStateMachine.create({ order })

  // Execute state transitions
  await machine.send('VALIDATE')
  await machine.send('PROCESS_PAYMENT')
  await machine.send('SHIP')

  return machine.state
})

State Persistence

State is automatically persisted between workflow steps, enabling durable execution:

Automatic Persistence

import { workflow, state } from 'sdk.do'

workflow('long-running-process', async ({ data }) => {
  // Step 1: Initialize state (persisted)
  await state.set('current', 'STEP_1')
  const step1Result = await performStep1(data)
  await state.set('step1Result', step1Result)

  // If process crashes here, workflow resumes from Step 2
  // State is automatically restored

  // Step 2: Use persisted state (persisted)
  await state.set('current', 'STEP_2')
  const step1Data = await state.get('step1Result')
  const step2Result = await performStep2(step1Data)
  await state.set('step2Result', step2Result)

  // Step 3: Complete (persisted)
  await state.set('current', 'STEP_3')
  const step2Data = await state.get('step2Result')
  return await performStep3(step2Data)
})

State Recovery

Workflows automatically recover from failures using persisted state:

import { workflow, state } from 'sdk.do'

workflow('resilient-process', async ({ order }) => {
  // Check current state
  const currentState = await state.get('current')

  // Resume from last successful state
  if (currentState === 'PAYMENT_FAILED') {
    // Retry payment
    const payment = await processPayment(order)
    await state.set('payment', payment)
    await state.set('current', 'PAYMENT_COMPLETED')
  }

  if (currentState === 'PAYMENT_COMPLETED') {
    // Continue to shipping
    const payment = await state.get('payment')
    await createShipment(order, payment)
    await state.set('current', 'SHIPPED')
  }

  // Workflow continues from current state
})

State Snapshots

Capture complete state snapshots for rollback:

import { workflow, state } from 'sdk.do'

workflow('transaction-workflow', async ({ transaction }) => {
  // Snapshot state before risky operation
  const snapshot = await state.snapshot()

  try {
    // Attempt risky operation
    await performRiskyOperation(transaction)
    await state.set('status', 'COMPLETED')
  } catch (error) {
    // Rollback to snapshot on failure
    await state.restore(snapshot)
    await state.set('status', 'FAILED')
    throw error
  }
})

State Patterns

Hierarchical State Machines (Statecharts)

Complex workflows use nested state machines:

import { state } from 'sdk.do'

const orderStatechart = state.machine({
  initial: 'PROCESSING',
  states: {
    PROCESSING: {
      initial: 'VALIDATING',
      states: {
        VALIDATING: {
          on: { SUCCESS: 'PAYMENT' },
        },
        PAYMENT: {
          initial: 'AUTHORIZING',
          states: {
            AUTHORIZING: {
              on: { SUCCESS: 'CAPTURING' },
            },
            CAPTURING: {
              on: { SUCCESS: '#PROCESSING.SHIPPING' },
            },
          },
        },
        SHIPPING: {
          on: { SUCCESS: '#COMPLETED' },
        },
      },
    },
    COMPLETED: {
      type: 'final',
    },
  },
})

Parallel States

Execute multiple state machines concurrently:

import { state, workflow } from 'sdk.do'

workflow('onboard-customer', async ({ customer }) => {
  // Run multiple state machines in parallel
  const [account, profile, notifications] = await Promise.all([
    // Account setup state machine
    state
      .machine({
        initial: 'CREATING_ACCOUNT',
        states: {
          CREATING_ACCOUNT: {
            on: { SUCCESS: 'VERIFYING_EMAIL' },
          },
          VERIFYING_EMAIL: {
            on: { SUCCESS: 'ACCOUNT_READY' },
          },
          ACCOUNT_READY: {
            type: 'final',
          },
        },
      })
      .execute({ customer }),

    // Profile setup state machine
    state
      .machine({
        initial: 'GATHERING_INFO',
        states: {
          GATHERING_INFO: {
            on: { SUCCESS: 'PROFILE_COMPLETE' },
          },
          PROFILE_COMPLETE: {
            type: 'final',
          },
        },
      })
      .execute({ customer }),

    // Notifications setup state machine
    state
      .machine({
        initial: 'SETTING_PREFERENCES',
        states: {
          SETTING_PREFERENCES: {
            on: { SUCCESS: 'NOTIFICATIONS_READY' },
          },
          NOTIFICATIONS_READY: {
            type: 'final',
          },
        },
      })
      .execute({ customer }),
  ])

  return { account, profile, notifications }
})

Conditional States

States with conditional transitions:

import { state, workflow } from 'sdk.do'

workflow('approve-contract', async ({ contract }) => {
  const machine = state.machine({
    initial: 'PENDING_REVIEW',
    states: {
      PENDING_REVIEW: {
        on: {
          SUBMIT: [
            // Guard: Check if amount requires executive approval
            {
              target: 'EXECUTIVE_REVIEW',
              cond: (ctx) => ctx.contract.amount > 100000,
            },
            // Otherwise, standard approval
            {
              target: 'MANAGER_REVIEW',
            },
          ],
        },
      },
      MANAGER_REVIEW: {
        on: {
          APPROVE: 'APPROVED',
          REJECT: 'REJECTED',
        },
      },
      EXECUTIVE_REVIEW: {
        on: {
          APPROVE: 'APPROVED',
          REJECT: 'REJECTED',
          ESCALATE: 'BOARD_REVIEW',
        },
      },
      BOARD_REVIEW: {
        on: {
          APPROVE: 'APPROVED',
          REJECT: 'REJECTED',
        },
      },
      APPROVED: {
        type: 'final',
      },
      REJECTED: {
        type: 'final',
      },
    },
  })

  return await machine.execute({ contract })
})

State in Durable Workflows

State machines enable durable execution in workflows:

Workflow State Persistence

import { workflow, state } from 'sdk.do'

workflow('employee-onboarding', async ({ employee }) => {
  // Day 1: Welcome
  await state.transition('HIRED', 'WELCOMED', async () => {
    await sendWelcomeEmail(employee)
  })

  // Wait 7 days (state persisted during sleep)
  await sleep({ days: 7 })

  // Day 8: First check-in (resumed from persisted state)
  await state.transition('WELCOMED', 'FIRST_CHECKIN', async () => {
    await scheduleCheckIn(employee)
  })

  // Wait 30 days
  await sleep({ days: 30 })

  // Day 38: First review (resumed from persisted state)
  await state.transition('FIRST_CHECKIN', 'REVIEWED', async () => {
    await scheduleReview(employee)
  })

  // Wait 60 days
  await sleep({ days: 60 })

  // Day 98: Onboarding complete
  await state.transition('REVIEWED', 'ONBOARDED', async () => {
    await completeOnboarding(employee)
  })
})

Human-in-the-Loop States

Workflows wait in specific states for human decisions:

import { workflow, state, user } from 'sdk.do'

workflow('purchase-approval', async ({ purchase }) => {
  // Automatic state: Validate
  await state.transition('PENDING', 'VALIDATED', async () => {
    await validatePurchase(purchase)
  })

  // Human state: Await approval (workflow pauses here)
  const approval = await state.transition('VALIDATED', 'AWAITING_APPROVAL', async () => {
    return await user.requestApproval({
      type: 'purchase-approval',
      data: { purchaseId: purchase.id },
      timeout: { hours: 48 },
    })
  })

  // Conditional transition based on approval
  if (approval.approved) {
    await state.transition('AWAITING_APPROVAL', 'APPROVED', async () => {
      await processPurchase(purchase)
    })
  } else {
    await state.transition('AWAITING_APPROVAL', 'REJECTED', async () => {
      await notifyRejection(purchase)
    })
  }
})

State Observability

Track state transitions for monitoring and debugging:

State History

import { state, workflow } from 'sdk.do'

workflow('order-fulfillment', async ({ order }) => {
  // Enable state history tracking
  await state.enableHistory()

  await state.transition('RECEIVED', 'PROCESSING', async () => {
    await processOrder(order)
  })

  await state.transition('PROCESSING', 'SHIPPED', async () => {
    await shipOrder(order)
  })

  // Get state transition history
  const history = await state.getHistory()
  // [
  //   { from: 'RECEIVED', to: 'PROCESSING', at: '2025-01-01T10:00:00Z' },
  //   { from: 'PROCESSING', to: 'SHIPPED', at: '2025-01-01T11:00:00Z' }
  // ]

  return history
})

State Metrics

import { state, send } from 'sdk.do'

// Track state transitions for analytics
state.on('transition', async ({ from, to, duration }) => {
  await send($.Analytics.track, {
    event: 'state.transition',
    data: {
      from,
      to,
      duration,
      workflow: 'order-processing',
    },
  })
})

// Track state failures
state.on('failure', async ({ state, error }) => {
  await send($.Analytics.track, {
    event: 'state.failure',
    data: {
      state,
      error: error.message,
      workflow: 'order-processing',
    },
  })
})

SDK Object Integration

State machines integrate with workflow triggers and event handlers:

import { state, every, on, workflow } from 'sdk.do'

// EVERY - Scheduled state machine execution (every is 1 of 8 core SDK objects)
every('daily at 9am', async () => {
  const machine = state.machine({
    initial: 'GATHERING_DATA',
    states: {
      GATHERING_DATA: {
        on: { SUCCESS: 'GENERATING_REPORT' },
      },
      GENERATING_REPORT: {
        on: { SUCCESS: 'SENDING_REPORT' },
      },
      SENDING_REPORT: {
        on: { SUCCESS: 'COMPLETED' },
      },
      COMPLETED: {
        type: 'final',
      },
    },
  })

  await machine.execute()
})

// ON - Event-driven state transitions (on is 1 of 8 core SDK objects)
on($.Order.created, async ({ order }) => {
  const machine = state.machine({
    initial: 'VALIDATING',
    states: {
      VALIDATING: {
        on: { SUCCESS: 'PROCESSING' },
      },
      PROCESSING: {
        on: { SUCCESS: 'SHIPPED' },
      },
      SHIPPED: {
        on: { SUCCESS: 'COMPLETED' },
      },
      COMPLETED: {
        type: 'final',
      },
    },
  })

  await machine.execute({ order })
})

Core Capabilities

  • Finite State Machines - Well-defined states and transitions
  • State Persistence - Automatic state storage between steps
  • Error Recovery - Resume from last successful state
  • Hierarchical States - Nested state machines (statecharts)
  • Parallel States - Concurrent state machine execution
  • Conditional Transitions - Guards for state transitions
  • State History - Track state transition history
  • Durable Execution - Long-running workflows with persistent state

Access Methods

SDK

TypeScript/JavaScript library for state machine management

await state.transition('PENDING', 'PROCESSING', async () => {
  /* ... */
})

SDK Documentation

CLI

Command-line tool for state operations

do state get workflow-123 --key current

CLI Documentation

API

REST/RPC endpoints for state management

curl -X POST https://api.do/v1/state/workflow-123/transition -d '{"from":"PENDING","to":"PROCESSING"}'

API Documentation

MCP

Model Context Protocol for AI-driven state operations

Transition workflow state from PENDING to PROCESSING

MCP Documentation

Parent Concept

  • workflows - Workflows ARE code functions with state machines

SDK Object Mappings

  • every - Time-based state machine execution (SDK object - 1 of 8 core)
  • on - Event-driven state transitions (SDK object - 1 of 8 core)
  • functions - Functions use state for execution
  • agents - Agents maintain state across interactions
  • context - Context enriches state with meaning
  • database - Persistent state storage
  • events - State change events