Patterns
advancedorchestration Featured

State Machine Workflow

Model a business process as a set of defined states with explicit transitions between them. Unlike linear workflows, items can move forwards, backwards, and loop — matching how real business processes actually behave.

Views54
BPMN 2.0
On this page

Visual Flow

Rendering diagram…

When to Use This Pattern

Use a state machine when:

  • The process is non-linear — items can go backwards, loop, or skip steps
  • A simple "start to finish" workflow doesn't capture the real process (e.g., drafts can be rejected and revised multiple times)
  • You need to enforce valid transitions — not every state can lead to every other state
  • The item has a lifecycle with clear phases (Draft → Review → Approved → Published → Archived)

How It Works

Rendering diagram…

Implementation Guide

Step 1: Define States and Transitions

Map every possible state and every valid transition:

Current StateActionNext StateWho Can ActSide Effects
DraftSubmitIn ReviewAuthorNotify reviewer
In ReviewApproveApprovedReviewerNotify author
In ReviewRejectDraftReviewerNotify author with feedback
In ReviewRequest ChangesDraftReviewerNotify author with specific items
ApprovedPublishPublishedEditorPublish to website
ApprovedRevokeDraftManagerNotify all parties
PublishedArchiveArchivedAdminRemove from website
PublishedUnpublishApprovedEditorRemove from website, keep approved
AnyCancelCancelledAuthor + ManagerNotify all parties
Step 2: Implement the State Engine

The core loop:

WHILE state != terminal_state:
    valid_actions = get_valid_transitions(current_state, current_user_role)
    
    display_task(item, valid_actions)
    
    chosen_action = wait_for_user_response()
    
    IF chosen_action IN valid_actions:
        execute_side_effects(current_state, chosen_action)
        current_state = transition_table[current_state][chosen_action]
        log_transition(old_state, chosen_action, new_state, user, timestamp)
    ELSE:
        reject_invalid_action()
Step 3: Store the Transition Table Externally

Don't hardcode transitions in the workflow. Store them in a list or database:

From StateActionTo StateAllowed RolesEnabled
draftsubmitin-reviewauthorYes
in-reviewapproveapprovedreviewer,managerYes
in-reviewrejectdraftreviewer,managerYes

This lets business users modify the process without touching the workflow.

Step 4: Build the Task Form Dynamically

Show only the valid actions for the current state:

  1. Query the transition table for the current state
  2. Filter by the current user's role
  3. Display only those action buttons
  4. Include required fields for each action (e.g., "rejection reason" only shows when rejecting)
Step 5: Visualize the State History

Show the item's complete journey:

TimestampFromToActionByComment
Mar 15, 10:00DraftCreatedJaneInitial draft
Mar 15, 14:30DraftIn ReviewSubmitJaneReady for review
Mar 16, 09:15In ReviewDraftRejectBobNeeds budget section
Mar 16, 16:00DraftIn ReviewSubmitJaneBudget section added
Mar 17, 11:00In ReviewApprovedApproveBobLooks good

Tips & Best Practices

Warning

Avoid "god states" — a state that can transition to any other state. This defeats the purpose of having a state machine. If you need a "reset" action, create it as a specific transition from specific states.

  • Terminal states are final. Once an item reaches Archived, Cancelled, or Completed, no transitions should be possible. This provides data integrity.
  • Guard conditions. Some transitions might need additional conditions beyond role: "Can only publish if review score > 80%". Implement these as pre-transition checks.
  • Timeout transitions. Combine with Escalation with SLA Timeout — if an item sits in "In Review" for 5 days, auto-transition to "Escalated".
  • Version the state model. When you change the states/transitions, items already in-flight should continue with the old model. New submittals use the new model.

Related patterns