The aws:sfn/stateMachine:StateMachine resource, part of the Pulumi AWS provider, defines a Step Functions state machine: its workflow definition, execution type, and operational configuration. This guide focuses on three capabilities: Standard vs Express workflow types, CloudWatch Logs integration, and customer-managed encryption.
State machines require IAM execution roles with Step Functions trust policies and reference Lambda functions or other AWS services in their workflow definitions. The examples are intentionally small. Combine them with your own IAM roles, Lambda functions, and monitoring infrastructure.
Define a Standard workflow with Lambda tasks
Most deployments start with a Standard workflow that orchestrates Lambda functions or other AWS services, providing exactly-once execution for workflows that can run up to one year.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
// ...
const sfnStateMachine = new aws.sfn.StateMachine("sfn_state_machine", {
name: "my-state-machine",
roleArn: iamForSfn.arn,
definition: `{
\"Comment\": \"A Hello World example of the Amazon States Language using an AWS Lambda Function\",
\"StartAt\": \"HelloWorld\",
\"States\": {
\"HelloWorld\": {
\"Type\": \"Task\",
\"Resource\": \"${lambda.arn}\",
\"End\": true
}
}
}
`,
});
import pulumi
import pulumi_aws as aws
# ...
sfn_state_machine = aws.sfn.StateMachine("sfn_state_machine",
name="my-state-machine",
role_arn=iam_for_sfn["arn"],
definition=f"""{{
\"Comment\": \"A Hello World example of the Amazon States Language using an AWS Lambda Function\",
\"StartAt\": \"HelloWorld\",
\"States\": {{
\"HelloWorld\": {{
\"Type\": \"Task\",
\"Resource\": \"{lambda_["arn"]}\",
\"End\": true
}}
}}
}}
""")
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/sfn"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
// ...
_, err := sfn.NewStateMachine(ctx, "sfn_state_machine", &sfn.StateMachineArgs{
Name: pulumi.String("my-state-machine"),
RoleArn: pulumi.Any(iamForSfn.Arn),
Definition: pulumi.Sprintf(`{
\"Comment\": \"A Hello World example of the Amazon States Language using an AWS Lambda Function\",
\"StartAt\": \"HelloWorld\",
\"States\": {
\"HelloWorld\": {
\"Type\": \"Task\",
\"Resource\": \"%v\",
\"End\": true
}
}
}
`, lambda.Arn),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
// ...
var sfnStateMachine = new Aws.Sfn.StateMachine("sfn_state_machine", new()
{
Name = "my-state-machine",
RoleArn = iamForSfn.Arn,
Definition = @$"{{
\""Comment\"": \""A Hello World example of the Amazon States Language using an AWS Lambda Function\"",
\""StartAt\"": \""HelloWorld\"",
\""States\"": {{
\""HelloWorld\"": {{
\""Type\"": \""Task\"",
\""Resource\"": \""{lambda.Arn}\"",
\""End\"": true
}}
}}
}}
",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.sfn.StateMachine;
import com.pulumi.aws.sfn.StateMachineArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
// ...
var sfnStateMachine = new StateMachine("sfnStateMachine", StateMachineArgs.builder()
.name("my-state-machine")
.roleArn(iamForSfn.arn())
.definition("""
{
\"Comment\": \"A Hello World example of the Amazon States Language using an AWS Lambda Function\",
\"StartAt\": \"HelloWorld\",
\"States\": {
\"HelloWorld\": {
\"Type\": \"Task\",
\"Resource\": \"%s\",
\"End\": true
}
}
}
", lambda.arn()))
.build());
}
}
resources:
# ...
sfnStateMachine:
type: aws:sfn:StateMachine
name: sfn_state_machine
properties:
name: my-state-machine
roleArn: ${iamForSfn.arn}
definition: |
{
\"Comment\": \"A Hello World example of the Amazon States Language using an AWS Lambda Function\",
\"StartAt\": \"HelloWorld\",
\"States\": {
\"HelloWorld\": {
\"Type\": \"Task\",
\"Resource\": \"${lambda.arn}\",
\"End\": true
}
}
}
The definition property contains the workflow logic in Amazon States Language, a JSON-based format that describes states and transitions. The roleArn grants the state machine permissions to invoke Lambda functions and other AWS services. Standard workflows (the default type) provide exactly-once execution semantics and full execution history.
Run high-throughput workflows with Express type
Express workflows handle high-volume event processing where at-least-once execution is acceptable, running for up to five minutes at lower cost than Standard workflows.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
// ...
const sfnStateMachine = new aws.sfn.StateMachine("sfn_state_machine", {
name: "my-state-machine",
roleArn: iamForSfn.arn,
type: "EXPRESS",
definition: `{
\"Comment\": \"A Hello World example of the Amazon States Language using an AWS Lambda Function\",
\"StartAt\": \"HelloWorld\",
\"States\": {
\"HelloWorld\": {
\"Type\": \"Task\",
\"Resource\": \"${lambda.arn}\",
\"End\": true
}
}
}
`,
});
import pulumi
import pulumi_aws as aws
# ...
sfn_state_machine = aws.sfn.StateMachine("sfn_state_machine",
name="my-state-machine",
role_arn=iam_for_sfn["arn"],
type="EXPRESS",
definition=f"""{{
\"Comment\": \"A Hello World example of the Amazon States Language using an AWS Lambda Function\",
\"StartAt\": \"HelloWorld\",
\"States\": {{
\"HelloWorld\": {{
\"Type\": \"Task\",
\"Resource\": \"{lambda_["arn"]}\",
\"End\": true
}}
}}
}}
""")
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/sfn"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
// ...
_, err := sfn.NewStateMachine(ctx, "sfn_state_machine", &sfn.StateMachineArgs{
Name: pulumi.String("my-state-machine"),
RoleArn: pulumi.Any(iamForSfn.Arn),
Type: pulumi.String("EXPRESS"),
Definition: pulumi.Sprintf(`{
\"Comment\": \"A Hello World example of the Amazon States Language using an AWS Lambda Function\",
\"StartAt\": \"HelloWorld\",
\"States\": {
\"HelloWorld\": {
\"Type\": \"Task\",
\"Resource\": \"%v\",
\"End\": true
}
}
}
`, lambda.Arn),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
// ...
var sfnStateMachine = new Aws.Sfn.StateMachine("sfn_state_machine", new()
{
Name = "my-state-machine",
RoleArn = iamForSfn.Arn,
Type = "EXPRESS",
Definition = @$"{{
\""Comment\"": \""A Hello World example of the Amazon States Language using an AWS Lambda Function\"",
\""StartAt\"": \""HelloWorld\"",
\""States\"": {{
\""HelloWorld\"": {{
\""Type\"": \""Task\"",
\""Resource\"": \""{lambda.Arn}\"",
\""End\"": true
}}
}}
}}
",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.sfn.StateMachine;
import com.pulumi.aws.sfn.StateMachineArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
// ...
var sfnStateMachine = new StateMachine("sfnStateMachine", StateMachineArgs.builder()
.name("my-state-machine")
.roleArn(iamForSfn.arn())
.type("EXPRESS")
.definition("""
{
\"Comment\": \"A Hello World example of the Amazon States Language using an AWS Lambda Function\",
\"StartAt\": \"HelloWorld\",
\"States\": {
\"HelloWorld\": {
\"Type\": \"Task\",
\"Resource\": \"%s\",
\"End\": true
}
}
}
", lambda.arn()))
.build());
}
}
resources:
# ...
sfnStateMachine:
type: aws:sfn:StateMachine
name: sfn_state_machine
properties:
name: my-state-machine
roleArn: ${iamForSfn.arn}
type: EXPRESS
definition: |
{
\"Comment\": \"A Hello World example of the Amazon States Language using an AWS Lambda Function\",
\"StartAt\": \"HelloWorld\",
\"States\": {
\"HelloWorld\": {
\"Type\": \"Task\",
\"Resource\": \"${lambda.arn}\",
\"End\": true
}
}
}
Setting type to EXPRESS changes the execution model: Express workflows run with at-least-once semantics, lower latency, and reduced cost. They’re designed for high-throughput scenarios like streaming data processing or IoT telemetry.
Send execution history to CloudWatch Logs
Production workflows need visibility into execution history for debugging and compliance. Step Functions sends execution events to CloudWatch Logs with configurable detail levels.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
// ...
const sfnStateMachine = new aws.sfn.StateMachine("sfn_state_machine", {
name: "my-state-machine",
roleArn: iamForSfn.arn,
definition: `{
\"Comment\": \"A Hello World example of the Amazon States Language using an AWS Lambda Function\",
\"StartAt\": \"HelloWorld\",
\"States\": {
\"HelloWorld\": {
\"Type\": \"Task\",
\"Resource\": \"${lambda.arn}\",
\"End\": true
}
}
}
`,
loggingConfiguration: {
logDestination: `${logGroupForSfn.arn}:*`,
includeExecutionData: true,
level: "ERROR",
},
});
import pulumi
import pulumi_aws as aws
# ...
sfn_state_machine = aws.sfn.StateMachine("sfn_state_machine",
name="my-state-machine",
role_arn=iam_for_sfn["arn"],
definition=f"""{{
\"Comment\": \"A Hello World example of the Amazon States Language using an AWS Lambda Function\",
\"StartAt\": \"HelloWorld\",
\"States\": {{
\"HelloWorld\": {{
\"Type\": \"Task\",
\"Resource\": \"{lambda_["arn"]}\",
\"End\": true
}}
}}
}}
""",
logging_configuration={
"log_destination": f"{log_group_for_sfn['arn']}:*",
"include_execution_data": True,
"level": "ERROR",
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/sfn"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
// ...
_, err := sfn.NewStateMachine(ctx, "sfn_state_machine", &sfn.StateMachineArgs{
Name: pulumi.String("my-state-machine"),
RoleArn: pulumi.Any(iamForSfn.Arn),
Definition: pulumi.Sprintf(`{
\"Comment\": \"A Hello World example of the Amazon States Language using an AWS Lambda Function\",
\"StartAt\": \"HelloWorld\",
\"States\": {
\"HelloWorld\": {
\"Type\": \"Task\",
\"Resource\": \"%v\",
\"End\": true
}
}
}
`, lambda.Arn),
LoggingConfiguration: &sfn.StateMachineLoggingConfigurationArgs{
LogDestination: pulumi.Sprintf("%v:*", logGroupForSfn.Arn),
IncludeExecutionData: pulumi.Bool(true),
Level: pulumi.String("ERROR"),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
// ...
var sfnStateMachine = new Aws.Sfn.StateMachine("sfn_state_machine", new()
{
Name = "my-state-machine",
RoleArn = iamForSfn.Arn,
Definition = @$"{{
\""Comment\"": \""A Hello World example of the Amazon States Language using an AWS Lambda Function\"",
\""StartAt\"": \""HelloWorld\"",
\""States\"": {{
\""HelloWorld\"": {{
\""Type\"": \""Task\"",
\""Resource\"": \""{lambda.Arn}\"",
\""End\"": true
}}
}}
}}
",
LoggingConfiguration = new Aws.Sfn.Inputs.StateMachineLoggingConfigurationArgs
{
LogDestination = $"{logGroupForSfn.Arn}:*",
IncludeExecutionData = true,
Level = "ERROR",
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.sfn.StateMachine;
import com.pulumi.aws.sfn.StateMachineArgs;
import com.pulumi.aws.sfn.inputs.StateMachineLoggingConfigurationArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
// ...
var sfnStateMachine = new StateMachine("sfnStateMachine", StateMachineArgs.builder()
.name("my-state-machine")
.roleArn(iamForSfn.arn())
.definition("""
{
\"Comment\": \"A Hello World example of the Amazon States Language using an AWS Lambda Function\",
\"StartAt\": \"HelloWorld\",
\"States\": {
\"HelloWorld\": {
\"Type\": \"Task\",
\"Resource\": \"%s\",
\"End\": true
}
}
}
", lambda.arn()))
.loggingConfiguration(StateMachineLoggingConfigurationArgs.builder()
.logDestination(String.format("%s:*", logGroupForSfn.arn()))
.includeExecutionData(true)
.level("ERROR")
.build())
.build());
}
}
resources:
# ...
sfnStateMachine:
type: aws:sfn:StateMachine
name: sfn_state_machine
properties:
name: my-state-machine
roleArn: ${iamForSfn.arn}
definition: |
{
\"Comment\": \"A Hello World example of the Amazon States Language using an AWS Lambda Function\",
\"StartAt\": \"HelloWorld\",
\"States\": {
\"HelloWorld\": {
\"Type\": \"Task\",
\"Resource\": \"${lambda.arn}\",
\"End\": true
}
}
}
loggingConfiguration:
logDestination: ${logGroupForSfn.arn}:*
includeExecutionData: true
level: ERROR
The loggingConfiguration property controls what gets logged. The logDestination points to a CloudWatch Log Group (note the :* suffix required by Step Functions). The includeExecutionData flag determines whether input and output data appear in logs, and level controls verbosity (ERROR, ALL, or OFF).
Encrypt state machine data with customer-managed keys
Compliance requirements often mandate encryption using customer-managed KMS keys rather than AWS-managed keys.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
// ...
const sfnStateMachine = new aws.sfn.StateMachine("sfn_state_machine", {
name: "my-state-machine",
roleArn: iamForSfn.arn,
definition: `{
\"Comment\": \"A Hello World example of the Amazon States Language using an [AWS Lambda Function](/guides/how-to/aws-lambda-function/)\",
\"StartAt\": \"HelloWorld\",
\"States\": {
\"HelloWorld\": {
\"Type\": \"Task\",
\"Resource\": \"${lambda.arn}\",
\"End\": true
}
}
}
`,
encryptionConfiguration: {
kmsKeyId: kmsKeyForSfn.arn,
type: "CUSTOMER_MANAGED_KMS_KEY",
kmsDataKeyReusePeriodSeconds: 900,
},
});
import pulumi
import pulumi_aws as aws
# ...
sfn_state_machine = aws.sfn.StateMachine("sfn_state_machine",
name="my-state-machine",
role_arn=iam_for_sfn["arn"],
definition=f"""{{
\"Comment\": \"A Hello World example of the Amazon States Language using an AWS Lambda Function\",
\"StartAt\": \"HelloWorld\",
\"States\": {{
\"HelloWorld\": {{
\"Type\": \"Task\",
\"Resource\": \"{lambda_["arn"]}\",
\"End\": true
}}
}}
}}
""",
encryption_configuration={
"kms_key_id": kms_key_for_sfn["arn"],
"type": "CUSTOMER_MANAGED_KMS_KEY",
"kms_data_key_reuse_period_seconds": 900,
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/sfn"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
// ...
_, err := sfn.NewStateMachine(ctx, "sfn_state_machine", &sfn.StateMachineArgs{
Name: pulumi.String("my-state-machine"),
RoleArn: pulumi.Any(iamForSfn.Arn),
Definition: pulumi.Sprintf(`{
\"Comment\": \"A Hello World example of the Amazon States Language using an AWS [Lambda Function](/guides/how-to/aws-lambda-function/)\",
\"StartAt\": \"HelloWorld\",
\"States\": {
\"HelloWorld\": {
\"Type\": \"Task\",
\"Resource\": \"%v\",
\"End\": true
}
}
}
`, lambda.Arn),
EncryptionConfiguration: &sfn.StateMachineEncryptionConfigurationArgs{
KmsKeyId: pulumi.Any(kmsKeyForSfn.Arn),
Type: pulumi.String("CUSTOMER_MANAGED_KMS_KEY"),
KmsDataKeyReusePeriodSeconds: pulumi.Int(900),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
// ...
var sfnStateMachine = new Aws.Sfn.StateMachine("sfn_state_machine", new()
{
Name = "my-state-machine",
RoleArn = iamForSfn.Arn,
Definition = @$"{{
\""Comment\"": \""A Hello World example of the Amazon States Language using an AWS Lambda Function\"",
\""StartAt\"": \""HelloWorld\"",
\""States\"": {{
\""HelloWorld\"": {{
\""Type\"": \""Task\"",
\""Resource\"": \""{lambda.Arn}\"",
\""End\"": true
}}
}}
}}
",
EncryptionConfiguration = new Aws.Sfn.Inputs.StateMachineEncryptionConfigurationArgs
{
KmsKeyId = kmsKeyForSfn.Arn,
Type = "CUSTOMER_MANAGED_KMS_KEY",
KmsDataKeyReusePeriodSeconds = 900,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.sfn.StateMachine;
import com.pulumi.aws.sfn.StateMachineArgs;
import com.pulumi.aws.sfn.inputs.StateMachineEncryptionConfigurationArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
// ...
var sfnStateMachine = new StateMachine("sfnStateMachine", StateMachineArgs.builder()
.name("my-state-machine")
.roleArn(iamForSfn.arn())
.definition("""
{
\"Comment\": \"A Hello World example of the Amazon States Language using an AWS Lambda Function\",
\"StartAt\": \"HelloWorld\",
\"States\": {
\"HelloWorld\": {
\"Type\": \"Task\",
\"Resource\": \"%s\",
\"End\": true
}
}
}
", lambda.arn()))
.encryptionConfiguration(StateMachineEncryptionConfigurationArgs.builder()
.kmsKeyId(kmsKeyForSfn.arn())
.type("CUSTOMER_MANAGED_KMS_KEY")
.kmsDataKeyReusePeriodSeconds(900)
.build())
.build());
}
}
resources:
# ...
sfnStateMachine:
type: aws:sfn:StateMachine
name: sfn_state_machine
properties:
name: my-state-machine
roleArn: ${iamForSfn.arn}
definition: |
{
\"Comment\": \"A Hello World example of the Amazon States Language using an AWS Lambda Function\",
\"StartAt\": \"HelloWorld\",
\"States\": {
\"HelloWorld\": {
\"Type\": \"Task\",
\"Resource\": \"${lambda.arn}\",
\"End\": true
}
}
}
encryptionConfiguration:
kmsKeyId: ${kmsKeyForSfn.arn}
type: CUSTOMER_MANAGED_KMS_KEY
kmsDataKeyReusePeriodSeconds: 900
The encryptionConfiguration property enables customer-managed encryption. Set type to CUSTOMER_MANAGED_KMS_KEY and provide the kmsKeyId. The kmsDataKeyReusePeriodSeconds controls how often Step Functions requests new data keys from KMS (between 60 and 900 seconds).
Beyond these examples
These snippets focus on specific state machine features: Standard and Express workflow types, CloudWatch Logs integration, and customer-managed encryption. They’re intentionally minimal rather than full workflow orchestrations.
The examples reference pre-existing infrastructure such as IAM execution roles with Step Functions trust policies, Lambda functions referenced in state machine definitions, CloudWatch Log Groups, and KMS keys. They focus on configuring the state machine rather than provisioning everything around it.
To keep things focused, common state machine patterns are omitted, including:
- X-Ray distributed tracing (tracingConfiguration)
- Version publishing and aliases (publish property)
- State machine tags for organization
- Complex state machine definitions (parallel states, error handling, retries)
These omissions are intentional: the goal is to illustrate how each state machine feature is wired, not provide drop-in workflow modules. See the Step Functions StateMachine resource reference for all available configuration options.
Let's create AWS Step Functions State Machines
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Configuration & Types
type property determines the workflow type. STANDARD is the default and suitable for long-running workflows. EXPRESS workflows are optimized for high-volume, short-duration executions.type property is immutable once the state machine is created. To change from STANDARD to EXPRESS (or vice versa), you must create a new state machine.name must contain only 0-9, A-Z, a-z, -, and _ characters. The name property is immutable after creation.name for explicit naming or namePrefix for auto-generated names with a prefix, but not both. These properties conflict with each other.roleArn pointing to an IAM role that grants the state machine permissions to invoke the resources defined in your workflow (e.g., Lambda functions, other AWS services).Logging & Monitoring
loggingConfiguration defaults to OFF. You must explicitly configure logging to capture execution history events.loggingConfiguration with logDestination (CloudWatch log group ARN with :* suffix), includeExecutionData (true/false), and level (e.g., ERROR, ALL, FATAL, OFF).Security & Encryption
encryptionConfiguration with kmsKeyId (your KMS key ARN), type set to CUSTOMER_MANAGED_KMS_KEY, and optionally kmsDataKeyReusePeriodSeconds (e.g., 900 seconds).Versioning
publish to true during creation. This publishes a version of the state machine, and the version ARN is available in the stateMachineVersionArn output property.Using a different cloud?
Explore integration guides for other cloud providers: