AWS Step Functions Service Integrations: Building Workflows Without Custom Code
Learn how AWS Step Functions integrates with other AWS services like DynamoDB, Lambda, and SQS directly from within your workflow. See how to orchestrate real-world AWS services without writing extra glue code.
In the previous post, we looked at the fundamentals of AWS Step Functions — how workflows are structured, how states control execution, and how data moves between steps.
In this post, we're going a step further and see how Step Functions integrate with other AWS services — like DynamoDB, SQS, and Lambda — directly within your workflow.
I'll use a simple user onboarding demo to show this in action, but the real takeaway is understanding how you can use Step Functions to orchestrate real-world AWS services without writing extra glue code.
Thanks to AWS for sponsoring this article in my Step Function Series.
Let's build a user onboarding workflow that automatically handles the complete signup process - capturing registration data, storing profiles in DynamoDB, notifying systems via SQS, detecting referral codes with Choice states, and processing them through Lambda functions.
This workflow shows how Step Functions can orchestrate an entire process without writing any glue code to connect these services.
Creating the AWS Step Function State Machine
Let's head to the AWS Console under Step Functions and create a new state machine.
Choose Create from blank, select Standard workflow type, and give it a name like user-onboarding.
This opens the Step Functions visual builder where we can start adding states.
First, let's use a Pass state to set up variables that will be available throughout our workflow.
Drag a Pass state from the Flow section and configure it to extract user information from the workflow input.
In the Variables section, add:
user: {% $states.input.user %}
This creates a $user variable that contains all the user information from the input.
Our input will be structured like this:
{"user": {"userId": "user-12345","email": "john.doe@example.com","name": "John Doe","signupDate": "2025-10-20T10:30:00Z","source": "web_signup","metadata": {"referralCode": "FRIEND2025","country": "US"}}}
By setting the user variable in the first step, all subsequent steps can access this data using $user.userId, $user.email, etc.
Saving User to Amazon DynamoDB in Step Function
Now let's integrate with DynamoDB to save the user information.
Navigate to the Actions section in the visual builder. Here you'll see all the available AWS service integrations. The list is extensive — DynamoDB, Lambda, SQS, SNS, API Gateway, and many more.
Search for DynamoDB and drag the Put item action below your Pass state.
Configuring DynamoDB Put Item
For this demo, I've already created a DynamoDB table called User with a partition key (PK) and sort key (SK).
In the DynamoDB state configuration:
- Name it "Save User Details"
- Configure the arguments to specify the table name and item
Here's the complete arguments configuration:
{"TableName": "User","Item": {"PK": {"S": "{% $user.userId %}"},"SK": {"S": "PROFILE"},"userId": {"S": "{% $user.userId %}"},"email": {"S": "{% $user.email %}"},"name": {"S": "{% $user.name %}"},"signupDate": {"S": "{% $user.signupDate %}"},"source": {"S": "{% $user.source %}"},"metadata": {"M": {"referralCode": {"S": "{% $user.metadata.referralCode %}"},"country": {"S": "{% $user.metadata.country %}"}}}}}
Notice how we're using JSONata expressions to map values from our $user variable to the DynamoDB item structure.
The partition key uses the userId, and the sort key is a hard-coded string "PROFILE" for this demo. All other properties are mapped using the JSONata syntax {% $user.propertyName %}.
If you save the state machine at this stage, AWS will prompt you about required IAM permissions.
By default, it will suggest adding permissions for DynamoDB operations (Get, Put, Update, Delete). For production, you should limit this to just the operations you need (in this case, just Put).
Let's click Confirm to create the state machine with the necessary permissions.
Publish Event to SQS from Step Function
After saving the user to DynamoDB, let's raise a UserOnboarded event using SQS.
I've already created an SQS queue called user-onboarding for this demo.
Search for SQS in the Actions panel and drag Send message into your workflow below the DynamoDB state.
In the SQS state configuration:
- Name it "Send User Onboarded Event"
- Set the queue URL (you can select it from the dropdown or paste it)
- Configure the message body
Here's the message configuration:
{"type": "UserOnboarded","userId": "{% $user.userId %}","signupDate": "{% $user.signupDate %}","createdDate": "{% $now() %}"}
Notice we're using the $now() function from JSONata to automatically add the current timestamp.
Conditionally Triggering a Lambda Function in AWS Step Functions
Let's say we want to process users differently based on whether they have a referral code.
Drag a Choice state from the Flow section below the SQS state. Edit Rule 1 and set the condition to check if a referral code exists:
{% $exists($user.metadata.referralCode) and $length($user.metadata.referralCode) > 0 %}
This JSONata expression checks:
- If the
referralCodeproperty exists using$exists() - If it has a non-empty value using
$length()
For the Default path, add a Pass state called "No Action" (in a real workflow, you might have other logic here).
For the referral code path, let's invoke a Lambda function to process the referral.
Search for Lambda in Actions and drag Invoke into the workflow on the Rule 1 path.
Creating the Lambda Function
For this demo, I've created a simple Lambda function called user-onboarding that just logs the input:
public string Handler(Input input, ILambdaContext context){context.Logger.LogInformation($"User: {input.UserId}, Created: {input.Created}");return "Processed";}
Configuring Lambda Invoke in AWS Step Function
In the Lambda state configuration:
- Name it "Process Referral"
- Select your Lambda function from the dropdown
- Configure the payload
Here's the payload:
{"userId": "{% $user.userId %}","created": "{% $now() %}"}
Configuring IAM Permissions for Step Function
Now that we've added all the states, we need to configure the appropriate IAM permissions for Step Functions to interact with all the resources it needs to talk to.
Navigate to the state machine Configuration → Permissions → View role in IAM.
For the workflow to function properly, you'll need to add permissions for the following services:
- SQS: Add
SendMessagepermission to the Step Functions IAM role for your specific queue - Lambda: Add two permissions:
InvokeFunctionpermission in the Step Functions IAM role- Resource-based policy on the Lambda function allowing
states.amazonaws.comto invoke it
Navigate to the state machine IAM role and create inline policies for each service, specifying the ARNs of your specific resources.
Testing the Complete Workflow
With all states configured and permissions in place, you can now test the workflow.
Click Execute and pass in a user JSON object. Based on whether the user has a referral code, the workflow will take different paths:
- Without referral code: The workflow will save to DynamoDB, publish to SQS, and follow the default "No Action" path
- With referral code: The workflow will save to DynamoDB, publish to SQS, and invoke the Lambda function to process the referral
You can verify the execution by checking:
- DynamoDB - Navigate to your User table and explore items to see the new record
- SQS - Go to your queue, click Send and receive messages, and poll for messages to see the UserOnboarded event
- Lambda CloudWatch logs - Navigate to Lambda → Monitor → View CloudWatch logs to see the function execution output (only for the referral code path)