Skip to main content

AWS Step Functions: State Machine Design & ASL Guide

Step Functions orchestrates complex workflows across AWS services with built-in error handling, retries, and visual debugging โ€” no coordination code in Lambda. This guide covers ASL syntax, all state types, error handling patterns, and workflow design best practices.

โœ“ Complete ASL state reference โœ“ Error handling with Retry/Catch โœ“ Express vs Standard workflows โœ“ SDK direct integrations

ASL State Machine: Complete Example

{
  "Comment": "Order processing workflow",
  "StartAt": "ValidateOrder",
  "States": {
    "ValidateOrder": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:us-east-1:123456789:function:ValidateOrder",
      "Retry": [
        {
          "ErrorEquals": ["Lambda.ServiceException", "Lambda.AWSLambdaException"],
          "IntervalSeconds": 2,
          "MaxAttempts": 3,
          "BackoffRate": 2
        }
      ],
      "Catch": [
        {
          "ErrorEquals": ["ValidationError"],
          "Next": "SendRejectionEmail",
          "ResultPath": "$.error"
        }
      ],
      "Next": "ProcessPayment"
    },
    "ProcessPayment": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:us-east-1:123456789:function:ProcessPayment",
      "TimeoutSeconds": 30,
      "Next": "CheckPaymentStatus"
    },
    "CheckPaymentStatus": {
      "Type": "Choice",
      "Choices": [
        { "Variable": "$.paymentStatus", "StringEquals": "SUCCESS", "Next": "FulfillOrder" },
        { "Variable": "$.paymentStatus", "StringEquals": "PENDING", "Next": "WaitForPayment" }
      ],
      "Default": "SendFailureNotification"
    },
    "WaitForPayment": {
      "Type": "Wait",
      "Seconds": 300,
      "Next": "CheckPaymentStatus"
    },
    "FulfillOrder": {
      "Type": "Parallel",
      "Branches": [
        {
          "StartAt": "UpdateInventory",
          "States": {
            "UpdateInventory": {
              "Type": "Task",
              "Resource": "arn:aws:states:::dynamodb:updateItem",
              "Parameters": {
                "TableName": "Inventory",
                "Key": { "productId": { "S.$": "$.productId" } },
                "UpdateExpression": "SET quantity = quantity - :qty",
                "ExpressionAttributeValues": { ":qty": { "N.$": "$.quantity" } }
              },
              "End": true
            }
          }
        },
        {
          "StartAt": "SendConfirmationEmail",
          "States": {
            "SendConfirmationEmail": {
              "Type": "Task",
              "Resource": "arn:aws:states:::sns:publish",
              "Parameters": {
                "TopicArn": "arn:aws:sns:us-east-1:123456789:OrderConfirmations",
                "Message.$": "States.Format('Order {} confirmed!', $.orderId)"
              },
              "End": true
            }
          }
        }
      ],
      "End": true
    },
    "SendRejectionEmail": { "Type": "Succeed" },
    "SendFailureNotification": { "Type": "Fail", "Error": "PaymentFailed" }
  }
}

Standard vs Express Workflow Comparison

Feature Standard Workflow Express Workflow
Max duration1 year5 minutes
Execution semanticsExactly-onceAt-least-once
Pricing$0.025/1K transitions$1.00/M executions + duration
Execution history90 days in consoleCloudWatch Logs only
Throughput2,000 executions/sec100,000 executions/sec
Best forOrders, approvals, long processesHigh-volume event processing

Map State: Process Arrays in Parallel

// Map state processes each item in an array concurrently
{
  "ProcessOrders": {
    "Type": "Map",
    "ItemsPath": "$.orders",        // Array to iterate
    "MaxConcurrency": 10,           // Max parallel branches
    "Parameters": {
      "orderId.$": "$$.Map.Item.Value.id",
      "amount.$": "$$.Map.Item.Value.amount"
    },
    "Iterator": {
      "StartAt": "ProcessSingleOrder",
      "States": {
        "ProcessSingleOrder": {
          "Type": "Task",
          "Resource": "arn:aws:lambda:us-east-1:123456789:function:ProcessOrder",
          "End": true
        }
      }
    },
    "ResultPath": "$.processedOrders",
    "Next": "SendSummary"
  }
}

// Use case: process 100 orders in batches of 10 concurrently
// Much faster than sequential processing
// MaxConcurrency: 0 = unbounded parallelism
Share this tool: X / Twitter LinkedIn
โœ“ 60,000+ developers use DevPlaybook โ˜…โ˜…โ˜…โ˜…โ˜… 4.8 / 5 on Gumroad โœ“ MIT licensed ยท Instant download โœ“ No login required

Related Products

on Gumroad

You Might Also Need

More Free Tools

Enjoying this tool? Get more like it.

Weekly developer tool guides, productivity playbooks & AI tricks. Free. No spam.

DevPlaybook Pro 7 days free

Unlock AI-Powered Dev Tools

  • โšก AI Code Review, Doc Generator & SQL Builder
  • โšก All premium templates & early access
  • โšก Member discounts on Gumroad products
Start Free Trial โ†’

$9/mo after trial ยท Cancel anytime

Want the full toolkit?

Get DevPlaybook Pro

Every template, guide, boilerplate, and automation script in one bundle. 13 premium products โ€” grab them all at once and save big.

$79
$241 separately Save $162 (67% off)
Get DevPlaybook Pro โ€” $79 โ†’

MIT licensed ยท Instant download ยท No subscription

See what's included โ†’ Browse all deals โ†’

Frequently Asked Questions

What is AWS Step Functions?▼

AWS Step Functions is a serverless orchestration service that coordinates multiple AWS services (Lambda, DynamoDB, SQS, ECS, etc.) into a workflow defined in Amazon States Language (ASL). Instead of writing complex coordination logic inside Lambda functions, Step Functions manages state, retries, error handling, and parallel execution through a visual state machine. It is ideal for multi-step workflows, long-running processes, and distributed transactions.

What is the difference between Standard and Express workflows?▼

Standard workflows support execution durations up to 1 year, have exactly-once execution semantics, and store full execution history in the console. They cost $0.025 per 1,000 state transitions. Express workflows support durations up to 5 minutes, have at-least-once semantics, stream logs to CloudWatch, and cost $1.00 per million workflow requests plus duration. Use Standard for human-approval workflows and long processes; use Express for high-volume, short-duration event processing.

What are the main state types in ASL?▼

ASL has 8 state types: Task (call a service or Lambda), Choice (conditional branching, like if/else), Parallel (run branches concurrently), Map (iterate over array items), Wait (pause for a time or timestamp), Pass (transform input/output), Succeed (end execution successfully), and Fail (end with error). Combining these states covers virtually all workflow patterns.

How does error handling work in Step Functions?▼

Each Task state can have Retry and Catch blocks. Retry specifies retry intervals and backoff rates for specific error types (Lambda.ServiceException, States.Timeout, etc.). Catch routes execution to a fallback state when retries are exhausted. This declarative error handling means you do not need to write retry logic in Lambda code โ€” the state machine handles it, making workflows more resilient and easier to debug.

What is the Step Functions SDK integration and why use it?▼

SDK integrations (also called optimized integrations or direct integrations) allow Step Functions to call AWS services like DynamoDB, SQS, SNS, or EventBridge directly โ€” without needing a Lambda function as a wrapper. This reduces Lambda invocations, lowers cost, and improves reliability. For example, writing to DynamoDB from a workflow step is cheaper and simpler via SDK integration than via a Lambda function that calls DynamoDB.

When should I use Step Functions vs SQS vs EventBridge?▼

Step Functions is best when you need explicit workflow visualization, complex branching logic, error handling across multiple steps, or human approval steps. SQS is best for simple message queuing between decoupled services with a Lambda consumer. EventBridge is best for event-driven architectures where multiple services react to events independently. For orchestration (one service directs others), use Step Functions. For choreography (services independently react), use EventBridge or SQS.