AWS serverless integration testing in 2026: 3 local setups that actually work

Step Functions Local is unsupported and LocalStack now needs a paid token. Three setups compared.

Read time
18 min
Word count
2.7K
Sections
10
FAQs
8
Share
Local test harness validating an AWS Step Functions workflow before deployment
Three local setups replace the unsupported Step Functions Local emulator in 2026.
On this page · 10 sections
  1. What actually changed, and when
  2. The three setups, compared
  3. What a LocalStack licence costs
  4. A decision table for picking one
  5. Migrating off Step Functions Local without a big-bang rewrite
  6. India-specific considerations
  7. What still does not work locally
  8. FAQ
  9. How eCorpIT can help
  10. References

Summary. Two changes broke the way most teams test event-driven AWS workloads locally. AWS now labels its own emulator page "Testing state machines with Step Functions Local (unsupported)" and tells readers to use the TestState API instead; the downloadable JAR still reports Version 2.0.0, Build 2024-05-18. And on 23 March 2026, LocalStack for AWS 2026.03.0 merged its free community image into the paid one, making an auth token mandatory to start the container, with a temporary bypass that expired on 6 April 2026. Paid seats run $39 per licence per month billed annually, $45 billed monthly, or $89 for the Ultimate tier that carries 110+ emulated services. The free Hobby tier survives for non-commercial use with 30+ services. Meanwhile the replacement AWS wants you on, the enhanced TestState API, launched on 19 November 2025 and costs nothing extra: "TestState API calls are included with AWS Step Functions at no additional charge." This article compares the three setups that remain viable, with the exact commands, the licence maths and the gaps each one still has.

What actually changed, and when

For years the default answer to "how do I test a Step Functions workflow without deploying" was docker run -p 8083:8083 amazon/aws-stepfunctions-local. That answer is dead. The AWS documentation page for Step Functions Local now opens with an unambiguous warning: "Step Functions Local does not provide feature parity and is unsupported. You might consider third party solutions that emulate Step Functions for testing purposes." The same page points readers at the TestState API as the alternative. The JAR is still downloadable, and it still runs, but java -jar StepFunctionsLocal.jar -v prints a build stamped 2024-05-18. Nothing shipped since. Any Amazon States Language feature added after that date is not in it.

The replacement landed on 19 November 2025, when AWS announced enhanced local testing through the TestState API. Donnie Prakoso, Principal Developer Advocate at AWS, wrote in the launch post: "These enhancements bring the familiar local development experience to Step Functions workflows, helping me to get instant feedback on changes before deploying to my AWS account." The launch added three things that matter for integration testing: mocking of service integrations, support for every state type including inline and distributed Map, Parallel, Activity, .sync and .waitForTaskToken, and the ability to test a named state inside a complete state machine definition using the stateName parameter.

The second change is commercial rather than technical. LocalStack had shipped two Docker images, localstack/localstack as a limited community build and localstack/localstack-pro for paying customers. Version 2026.03.0, released 23 March 2026, collapsed them: "as of version 2026.3.0 and going forward, localstack/localstack and localstack/localstack-pro on DockerHub will both contain the same image. The supported services will be determined by the entitlements associated with your personal auth token or CI auth token." An auth token became mandatory to start the container. Teams could set LOCALSTACK_ACKNOWLEDGE_ACCOUNT_REQUIREMENT=1 to defer the requirement, but only "until April 6, 2026". The same release moved LocalStack to calendar versioning (YYYY.MM.patch) and, in the other direction, removed CI credit limits from every tier including the free one.

One more detail from that release bites on upgrade: "Any state created with a version prior to 2026.03.0 will not be compatible and will need to be recreated. This applies to Cloud Pods, state snapshots, and PERSISTENCE=1." If your CI seeds a local environment from a saved Cloud Pod, that seed has to be rebuilt.

The three setups, compared

Setup What it can test Cost and main limit
Step Functions Local (JAR or archived Docker image) Basic state machine execution against local Lambda or overridden service endpoints Free, but marked unsupported by AWS with no feature parity; last build 2024-05-18
TestState API with mocks, via AWS CLI or SDK Individual states, every state type, retry and catch logic, Map tolerance thresholds, context objects for waitForTaskToken No extra charge on top of Step Functions; needs states:TestState IAM permission and a network call to the AWS endpoint
TestState API pointed at LocalStack The same tests with full network isolation on a developer laptop or air-gapped runner Needs a LocalStack licence from $39 per licence per month; some capabilities such as Parallel state testing may lag the AWS implementation
LocalStack plus AWS SAM CLI End-to-end event-driven flows across Lambda, SQS, EventBridge and DynamoDB deployed with sam deploy Licence cost as above; emulator behaviour is not guaranteed identical to the real service
AWS Toolkit for VS Code connected to LocalStack The same as above, driven from the IDE, with resource browsing and Lambda code editing against the local stack Free from AWS at v3.74.0 and later; the LocalStack licence still applies; not available in AWS GovCloud (US) Regions
A disposable AWS development account Everything, with real service behaviour and real IAM Real AWS charges and real deploy latency on every change

Most teams end up running two of these, not one. TestState with mocks covers workflow logic in unit tests that run in milliseconds and need no credentials. LocalStack covers the wiring between services. A dev account still catches the things only the real service does.

Setup 1: TestState with mocks, no AWS resources

This is the cheapest place to start because it needs no emulator and no deployed stack. A mocked call skips IAM entirely. The AWS documentation is explicit: "When you specify a mock, specifying the role becomes optional, allowing you to test state machine logic without configuring IAM permissions." The caller still needs permission to perform the states:TestState action; without mocking, it also needs iam:PassRole.

A minimal mocked test of a Lambda task state:


            aws stepfunctions test-state --region us-east-1 \
--definition '{
  "Type": "Task",
  "Resource": "arn:aws:states:::lambda:invoke",
  "Parameters": {"FunctionName": "process-order"},
  "End": true
}' \
--mock '{"result":"{\"orderId\":\"12345\",\"status\":\"processed\"}"}' \
--inspection-level DEBUG
          

TestState validates that mock against the Lambda service API model, so a mock with the wrong shape fails the test rather than passing a lie into the next state. Three validation modes are available through fieldValidationMode: STRICT, the default, which validates all required fields; PRESENT, which validates field types and names; and NONE. Mock validation is not supported for HTTP Task, API Gateway, EKS Call and EKS RunJob integrations.

Error paths use the same shape:


            aws stepfunctions test-state --region us-east-1 \
--definition '{
  "Type": "Task",
  "Resource": "arn:aws:states:::lambda:invoke",
  "Parameters": {"FunctionName": "process-order"},
  "End": true
}' \
--mock '{"errorOutput":{"error":"Lambda.ServiceException","cause":"Function failed"}}' \
--inspection-level DEBUG
          

Three inspection levels control what comes back. INFO, the default, returns the state output on success or the error output on failure. DEBUG adds an inspectionData object with input, afterInputPath, afterParameters, result, afterResultSelector, afterResultPath and output, which is what you assert against when you are debugging a data transformation. TRACE applies only to HTTP Task and returns the HTTP request Step Functions made and the response the API returned; using it on any other state type throws an error. All three levels return status and nextState, where status is one of SUCCEEDED, FAILED, RETRIABLE or CAUGHT_ERROR.

One trap worth knowing before you plan a migration: the console does not have these features. AWS states that "the console TestState feature does not yet support some of the enhancements described in this document, such as mocking service integrations, testing Map and Parallel states, or Activity, .sync and .waitForTaskToken patterns. These capabilities are currently available only through the TestState API using the AWS CLI or SDK." If your team's mental model of TestState comes from clicking around the console, it is out of date.

Setup 2: TestState in a pytest suite

AWS published a working reference implementation on 22 March 2026 in the Compute Blog, backed by a sample repository under the aws-samples organisation. It is Python 3.9 or later with pytest, MIT-0 licensed, and it models an ecommerce order flow using JSONata, distributed Map states, Parallel execution and a waitForTaskToken human approval step. Treat it as a pattern, not a product: the repository has 14 commits and no releases at the time of writing.

The part worth copying is the retry assertion. The enhanced API exposes stateConfiguration.retrierRetryCount on the request and inspectionData.errorDetails on the response, and that response block carries retryBackoffIntervalSeconds, retryIndex and catchIndex. That is enough to assert on exponential backoff arithmetic, which used to be untestable outside a real execution:


            def test_lambda_throttling_retry_mechanism(self, runner):
    """Test retry mechanism for Lambda.TooManyRequestsException"""
    throttling_error = {
        "Error": "Lambda.TooManyRequestsException",
        "Cause": "Request rate exceeded"
    }

    (runner
     .with_input({"orderId": "order-retry-test"})
     .with_mock_error(throttling_error)
     .with_retrier_retry_count(0)
     .execute("ValidateOrder")
     .assert_retriable()
     .assert_error("Lambda.TooManyRequestsException"))

    response = runner.get_response()
    error_details = response['inspectionData']['errorDetails']
    assert error_details['retryBackoffIntervalSeconds'] == 2
          

Distributed Map states get their own controls. stateConfiguration.mapIterationFailureCount simulates failing iterations, and the response returns inspectionData.toleratedFailureCount and inspectionData.toleratedFailurePercentage. When the simulated failures exceed the configured tolerance, the API returns States.ExceedToleratedFailureThreshold, so a test can prove that a Map state fails at the threshold you configured rather than the one you assumed.

The sample repository wires this into CI with .github/workflows/test-and-deploy.yml, a two-stage pipeline that runs pytest tests/unit_test.py first and only then runs sam build and sam deploy. It uses AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and AWS_REGION as repository secrets. Long-lived access keys in CI are a poor default in 2026; the shape of the pipeline is right, the credential mechanism is worth replacing with OIDC before you copy it.

Setup 3: LocalStack for network-isolated runs

AWS and LocalStack partnered on this path. The Compute Blog is direct about it: "We've partnered with LocalStack to offer an additional testing endpoint for the TestState API. Developers can use LocalStack for unit testing their workflows by changing the AWS SDK client endpoint configuration to point to LocalStack: http://localhost.localstack.cloud:4566/ instead of AWS endpoint. This approach provides complete network isolation when needed."

In practice that is one line in a boto3 client:


            import boto3

client = boto3.client(
    'stepfunctions',
    region_name='us-east-1',
    endpoint_url='http://localhost.localstack.cloud:4566'
)
          

The sample repository carries a caveat that should go into your decision record verbatim: "As LocalStack continues to expand support for Enhanced TestState API features, some capabilities such as Parallel state testing may not yet be available in their emulated environment at the time of publishing." LocalStack has been closing that gap; the 2026.03.0 notes record that "the StepFunctions TestState API now supports Parallel state with mocked results, allowing you to test parallel states in isolation without executing branches," and that the same API "now correctly interpolate variables in JSONata-based states." The lesson is to pin a version and re-test when you bump it, not to assume parity.

For the IDE path there are two separate extensions and it is easy to confuse them. The AWS Toolkit for VS Code gained the ability to connect to custom endpoints such as LocalStack in v3.74.0; AWS described the significance plainly: "The key benefit of this integration is that AWS Toolkit for VS Code can now connect to custom endpoints such as LocalStack, something that wasn't possible before." That integration is available in all commercial AWS Regions except AWS GovCloud (US) Regions, and AWS charges nothing for it. Separately, the LocalStack Toolkit for VS Code "enables you to install, configure, and run LocalStack without leaving VS Code" and "automatically configures a dedicated localstack AWS profile in your .aws/config and .aws/credentials files, if one is not already present." It exposes commands including localstack.setup, localstack.start, localstack.stop and localstack.viewLogs, and it is included in the Hobby, Base and Ultimate plans.

Once the profile exists, SAM behaves normally:


            sam deploy --guided --profile localstack
aws --profile localstack sqs list-queues
          

What a LocalStack licence costs

Plan Price What you get
Hobby Free 30+ emulated services, 1 personal sandbox, CI runs, VS Code integration, non-commercial use only
Base, billed annually $39 per licence per month 55+ emulated services, a sandbox per developer, local state persistence, basic IAM policy enforcement
Base, billed monthly $45 per licence per month Same feature set as annual Base, purchased by credit card
Ultimate, billed annually $89 per licence per month 110+ emulated services, advanced IAM policy testing, live AWS resource replicator, priority support
Enterprise Custom Air-gapped image delivery, Kubernetes delivery, GovCloud, custom SSO and SCIM, unlimited users

All prices are quoted in USD on the LocalStack pricing page. Cloud Pod storage and application-preview minutes are allotted to the workspace rather than to individual licences, which matters when you size a team plan: eight engineers on Base share the same 300 MB of state storage per workspace.

Run the arithmetic before the procurement conversation. A ten-engineer team on Base billed annually is $39 × 10 × 12, or $4,680 a year. The same team on Ultimate is $10,680. Those numbers are only worth paying if they displace something. The honest comparison is not LocalStack against zero, it is LocalStack against the cost of a shared development AWS account plus the engineering hours lost to five-minute deploy cycles. The real cost is usually the feedback loop, not the licence.

There is a free path that many teams miss. The Hobby tier "supports the equivalent functionality of the prior community image" for non-commercial use, and LocalStack runs a separate open-source licence programme for maintainers of community projects. Neither covers commercial product work.

A decision table for picking one

Situation Setup to reach for Why
Asserting on retry counts, backoff intervals and catch branches TestState with mocks in pytest or Jest No IAM, no deployed resources, and inspectionData.errorDetails exposes the values directly
Verifying that an EventBridge rule actually delivers to an SQS queue LocalStack with SAM TestState covers a state machine, not the wiring between services
Air-gapped or regulated environment with no outbound AWS access LocalStack, with the TestState endpoint override "Complete network isolation when needed" is the stated design goal
Confirming a new Amazon States Language feature behaves as documented A disposable AWS development account Emulators lag the service; Step Functions Local has lagged since 2024
Trying to keep an existing Step Functions Local suite alive Migrate it AWS says the tool is unsupported and does not provide feature parity
Cost-sensitive team with fewer than three engineers on serverless TestState mocks first, LocalStack later TestState adds no charge; the licence only pays for itself once cross-service wiring is the bottleneck

Migrating off Step Functions Local without a big-bang rewrite

Teams with an existing suite against port 8083 do not need to rewrite everything in one sprint. A workable sequence:

  1. Inventory what each existing test actually asserts. In most suites a large share are checking state transitions and error handling, both of which map cleanly onto TestState with mocks.
  1. Port the transition and error-handling tests first. They need no emulator, so they can run in CI immediately with only states:TestState permission.
  1. Keep the cross-service tests on the old harness until a LocalStack decision is made. They are the ones that need an emulator.
  1. Pin a LocalStack calendar version explicitly, for example localstack/localstack-pro:2026.06.0, and treat a version bump as a change that requires the suite to be re-run. The move to YYYY.MM.patch versioning means latest now shifts monthly.
  1. Rebuild any Cloud Pods or persisted state created before 2026.03.0, since those artefacts are not compatible with the current image.
  1. Delete the Step Functions Local harness once its last test has a home. Leaving an unsupported emulator in CI is how a suite quietly stops reflecting reality.

The same principle that governs durable execution choices between Lambda and Step Functions applies here: pick the layer that owns the behaviour you are asserting, and test it there rather than pushing everything into one harness.

India-specific considerations

Two points matter for teams building from India.

The first is data handling. Under the Digital Personal Data Protection Act 2023, test fixtures that contain real customer records are still personal data, and copying a production extract into a shared development AWS account creates an exposure that is hard to argue away later. Local emulation changes that calculus: with TestState mocks there is no data at all, only a schema-validated stub, and with LocalStack the traffic stays on the developer's machine. AWS's own framing of the LocalStack endpoint override is that it "provides complete network isolation when needed." Design your fixtures as synthetic from the start and the compliance question mostly disappears.

The second is the licence maths against local salaries. A $39 per licence per month seat is a smaller line item in a US budget than in an Indian one, where it is a larger fraction of a junior engineer's monthly cost. That pushes the sensible sequence for most Indian teams towards TestState mocks first, because they add nothing to the bill, with LocalStack seats bought only for the engineers who genuinely need cross-service emulation rather than for the whole team. It is the same discipline that shows up in cutting cloud spend for Indian teams: buy the seat for the bottleneck, not for the org chart.

Teams that run heavy CI matrices get an unexpected win here. LocalStack removed CI credit limits from all tiers in 2026.03.0, "including the non-commercial free tier (subject to our fair use policy)," so the old pattern of rationing emulator runs across pipelines no longer applies.

What still does not work locally

Be honest with the team about the gaps, because a green local suite that hides a production failure is worse than no suite.

Emulators approximate. LocalStack spawns real containers for some EC2 Fleet operations as of 2026.03.0, and its Step Functions support has improved release over release, but the sample repository's own caveat about Parallel state support lagging is a reminder that parity is a moving target rather than a guarantee. Anything where you are testing the service's behaviour, rather than your own logic, belongs in a real account.

TestState tests one state at a time. The chaining pattern in the AWS sample, where get_output() feeds the next execute() call, simulates a workflow but does not run one. Timing, concurrency in distributed Map, and anything that depends on the actual execution engine are outside its scope.

IAM is the classic blind spot. Mocked TestState calls skip role validation entirely, which is exactly what makes them fast, and exactly why a workflow that passes every local test can still fail on the first real execution with an AccessDenied. LocalStack's Base tier offers basic IAM policy enforcement and Ultimate adds advanced IAM policy testing, which is one of the clearer reasons to pay for the higher tier. Otherwise, keep a smoke test in a real account that exercises the permission boundary, and treat that smoke test the way you would treat any other on-call and SRE cost decision: it exists to catch the failure mode that the cheap layer cannot.

The same discipline that catches silent failures in AI agent evaluation pipelines applies to serverless suites: a test that cannot fail is not a test, and mocks make it easy to build a suite that cannot fail.

FAQ

How eCorpIT can help

eCorpIT builds and tests event-driven AWS workloads for teams that need a feedback loop faster than a deploy cycle. Our senior engineering teams migrate suites off unsupported emulators, wire TestState mocks and LocalStack into existing CI pipelines, and size licence spend against the bottleneck rather than the headcount. We are an ISO 27001:2022 certified, CMMI Level 5 organisation, and we design applications aligned with DPDP Act requirements so test fixtures never carry real customer data. If your serverless suite has stopped reflecting production, talk to us about a review, or see how we approach QA and test automation.

References

  1. AWS News Blog, Accelerate workflow development with enhanced local testing in AWS Step Functions, 19 November 2025.
  1. AWS Step Functions Developer Guide, Testing state machines with Step Functions Local (unsupported).
  1. AWS Step Functions Developer Guide, Testing a state using the TestState API.
  1. AWS Compute Blog, Testing Step Functions workflows: a guide to the enhanced TestState API, 22 March 2026.
  1. AWS Samples, sample-stepfunctions-testing-with-testStateAPI, GitHub repository.
  1. AWS News Blog, Accelerate serverless testing with LocalStack integration in VS Code IDE, 11 September 2025.
  1. LocalStack Blog, Announcing the LocalStack for AWS 2026.03.0 Release, 23 March 2026.
  1. LocalStack Blog, Announcing the LocalStack for AWS 2026.06.0 Release, 25 June 2026.
  1. LocalStack, Pricing.
  1. LocalStack Docs, LocalStack Toolkit for VS Code.
  1. AWS Step Functions API Reference, TestState.
  1. AWS Serverless Application Model Developer Guide, sam deploy.

Last updated: 3 August 2026.

Frequently asked

Quick answers.

01 Is AWS Step Functions Local deprecated?
AWS does not use the word deprecated, but the documentation page is titled "Testing state machines with Step Functions Local (unsupported)" and states that it does not provide feature parity and is unsupported. The page recommends the TestState API or third-party emulators instead. The downloadable JAR still reports Version 2.0.0, Build 2024-05-18.
02 Does the TestState API cost anything extra?
No. AWS stated at the November 2025 launch that TestState API calls are included with AWS Step Functions at no additional charge, and that enhanced TestState is available in all AWS Regions where Step Functions is supported. The caller needs permission for the states:TestState action, plus iam:PassRole when running without mocks.
03 Do I need IAM permissions to run mocked TestState calls?
You need states:TestState. Beyond that, AWS documents that specifying a mock makes the execution role optional, so you can test state machine logic without configuring IAM permissions for the downstream services. If you set revealSecrets to true you also need states:RevealSecrets, and that parameter cannot be combined with mocking.
04 Is LocalStack still free?
Only for non-commercial use. Since version 2026.03.0 on 23 March 2026, a single consolidated image requires an auth token, and the temporary bypass expired on 6 April 2026. The Hobby tier remains free with 30+ services. Base is $39 per licence per month billed annually or $45 monthly, and Ultimate is $89.
05 Which LocalStack tier do I need for Step Functions testing?
Base covers 55+ emulated services and basic IAM policy enforcement, which is enough for most workflow testing. Ultimate at $89 per licence per month adds 110+ services, advanced IAM policy testing and the live AWS resource replicator. Buy Ultimate only for engineers who need IAM verification or resource replication locally.
06 Can TestState test distributed Map and Parallel states?
Yes, through the API. The November 2025 enhancements added support for inline and distributed Map, Parallel, Activity, .sync and .waitForTaskToken patterns with mocked responses. AWS notes that the console TestState feature does not yet support mocking, Map, Parallel or those service integration patterns, so use the AWS CLI or an SDK.
07 How do I point the TestState API at LocalStack?
Change the SDK client endpoint. AWS documents http://localhost.localstack.cloud:4566/ as the LocalStack endpoint for TestState, and the AWS sample repository shows a boto3 client built with that endpoint_url. AWS describes the benefit as complete network isolation when needed. The LocalStack Toolkit for VS Code configures a matching localstack AWS profile automatically.
08 Will my old LocalStack Cloud Pods still work after upgrading?
No. The 2026.03.0 release notes state that any state created with a version prior to 2026.03.0 is not compatible and needs to be recreated, covering Cloud Pods, state snapshots and PERSISTENCE=1. LocalStack displays an explicit message when it tries to load incompatible state, so plan to rebuild those seeds during the upgrade.

About the author

Manu Shukla

Founder & Director

Founder of eCorpIT. Hands-on engineer leading senior-only delivery for AI apps, custom software, and cloud systems for global clients.

Subscribe

One engineering note a week. No fluff, no spam.

Senior-architect playbooks on AI agents, mobile apps, cloud, security, data, and marketing — delivered every Wednesday.

Past the reading

Read enough. Let's build something.

A senior architect responds in 24 working hours with scope, indicative cost, and a timeline. NDA before any technical conversation.