How to Test AWS Applications Locally and in CI with LocalStack
Use LocalStack to run repeatable AWS integration tests on a developer machine and in CI. Configure endpoints, provision test resources, capture logs, and understand what the emulator does not validate.
LocalStack lets you run integration tests against emulated AWS APIs on your machine or in a CI job. The repeatable loop is: start LocalStack, point your AWS tooling at its endpoint, create the resources your tests need, run the application tests, then retain logs and reports. This validates the interactions covered by the emulated services; it does not prove behavior against every real AWS service, account configuration, or production condition.
For the documented local quickstart, you need Docker, a LocalStack account and Auth Token, and Terraform or the AWS CLI to deploy resources. LocalStack documents services including Lambda, DynamoDB, S3, and SQS, and reports support for more than 80 services. Check the coverage for the exact APIs and behaviors your application uses. LocalStack Getting Started
1. Choose a startup and endpoint strategy
For local development, LocalStack recommends its lstk CLI as a straightforward startup path. Docker Compose is useful when your team wants the container configuration checked into the project and reused by developers and CI. Pin the LocalStack image version when repeatability matters. Both routes depend on a working Docker daemon; services that launch additional containers can also require Docker socket access.
| Choice | Use it when | Trade-off |
|---|---|---|
lstk |
You want an integrated install, authentication, and startup workflow. | Startup is driven by the CLI rather than solely by a checked-in Compose file. |
| Docker Compose | Your team wants reusable declarative container configuration. | You manage the container configuration and startup lifecycle directly. |
| Explicit SDK endpoint | You want the test target visible in application or test setup. | Your test configuration must supply a LocalStack endpoint. |
| Endpoint injection | You want to avoid changing application code, following LocalStack’s documented integration approach. | How the endpoint is selected is less visible in the application configuration; make the test environment explicit. |
LocalStack documents http://localhost.localstack.cloud:4566 and http://localhost:4566 as endpoint forms. Use the one that fits your local and runner networking setup. The endpoint a containerized test can reach may differ from the endpoint available to a process running directly on the host.
2. Start LocalStack on your machine
- Install and start Docker.
- Install the LocalStack CLI using the official installation guide.
- Authenticate with your LocalStack account and Auth Token as directed by the CLI.
- Start the environment and wait for it to report readiness.
lstk start
The local quickstart uses the endpoint localhost.localstack.cloud:4566. Keep startup output in your terminal while diagnosing connection or initialization problems. The CLI also provides lstk aws and lstk terraform wrappers for routing commands to the local service; consult the local development guide for the current command syntax and setup.
3. Point your application and test tools at the emulator
Configure the AWS client used by the integration tests to use a LocalStack endpoint. Keep this setting in test configuration, an environment variable, or a test-only client factory so a test run cannot accidentally target a real AWS endpoint. The exact option name depends on the AWS SDK and service client; use the SDK’s endpoint configuration mechanism described in LocalStack’s AWS SDK guide.
Alternatively, use LocalStack’s endpoint injection approach if it suits your project. LocalStack describes injection as a way to connect SDK traffic without changing application code. Whichever approach you choose, make the selection explicit in the test harness and verify the resolved endpoint before provisioning resources.
# Example environment values for a test process; adapt to your test harness.
AWS_ACCESS_KEY_ID=test
AWS_SECRET_ACCESS_KEY=test
AWS_DEFAULT_REGION=us-east-1
LOCALSTACK_ENDPOINT=http://localhost.localstack.cloud:4566
These values illustrate a test-only configuration pattern; they are not credentials for AWS. Do not reuse test endpoint settings in a production deployment. If tests run in a container, confirm that the endpoint hostname resolves from that container, not just from the host.
4. Provision only the resources the tests need
Integration tests should create the queues, tables, buckets, functions, or other resources they exercise. Provision them through the same kind of tooling the project uses—such as the AWS CLI, an SDK, Terraform, or test setup—configured for the local endpoint. Prefer deterministic names and known initial contents. Make setup idempotent where possible, and clean up or reset state after each run so one test cannot silently depend on another run.
The LocalStack quickstart documents using lstk aws or lstk terraform to deploy to the local environment. Keep infrastructure setup close to the test code or in a checked-in IaC configuration so developers and CI create the same resources. Start with only the services and API operations the application needs, then check LocalStack’s current coverage for any service-specific behavior.
5. Run the integration tests and inspect failures
- Start LocalStack and wait for readiness.
- Provision the test resources against its endpoint.
- Run the application’s integration test command.
- On failure, inspect both the test report and LocalStack logs. Distinguish an application assertion failure from a provisioning, endpoint, container, or unsupported-operation problem.
- Reset or discard the environment before the next independent run.
For test suites that manage containerized dependencies, LocalStack documents language integrations through Testcontainers. Follow the integration guide for the language and lifecycle you use rather than assuming a generic container setup will handle startup and cleanup correctly.
6. Run LocalStack in CI
A CI job should use a protected secret for the Auth Token, start a fresh emulator, provision the test infrastructure, run tests, and export logs and reports before the runner ends. Most jobs should begin with clean state to avoid hidden dependencies. Use persistence or snapshots only when the pipeline deliberately needs state to cross job boundaries.
- Add the LocalStack Auth Token to the CI provider’s secret manager. Expose it to the job as
LOCALSTACK_AUTH_TOKEN; do not commit it in a workflow file. - Install
lstkand any test or IaC tools missing from the runner. - Confirm the job can access a working Docker daemon and socket where the services under test need to launch containers.
- Run
lstk start, then create the test infrastructure or load an intentional snapshot. - Run tests against the LocalStack endpoint.
- Export LocalStack logs and test reports even if a test step fails, then retain them as job artifacts.
LocalStack’s CI guidance describes ephemeral jobs, state management, and log handling in its CI pipelines overview and CI best practices. Treat a LocalStack container as job infrastructure: a runner shutdown ends its lifetime unless you have explicitly arranged persistence.
7. GitHub Actions considerations
For GitHub Actions, LocalStack’s current guide shows installing and driving lstk directly. Store the Auth Token in GitHub Secrets and provide it to the job as LOCALSTACK_AUTH_TOKEN. The guide says lstk start waits until the environment is ready, so follow its current workflow rather than adding a readiness loop without a reason.
Check the provider-specific constraints before choosing a runner. LocalStack’s guide says Windows runners cannot run LocalStack natively. It also notes that arm64 Lambda emulation may require QEMU and can make builds slower. Docker access, networking, operating system, architecture, and the AWS services under test all affect whether a runner is suitable. See the current GitHub Actions guide for its workflow and caveats.
8. Know what the tests establish
A passing LocalStack integration test is evidence that the application and test setup interacted successfully with the emulated APIs exercised by that run. It is not a comprehensive parity guarantee for AWS. The reviewed LocalStack overview documents supported services and use cases but does not establish complete behavioral equivalence for every API, account configuration, permission boundary, regional condition, or production failure mode.
Where production-specific behavior matters, include a separate validation against AWS in an appropriately controlled environment. Keep that boundary clear in test names and reports: local emulator tests provide fast, repeatable feedback; they do not replace every form of cloud validation.
9. Performance, reliability, and cost considerations
- Keep jobs independent. A clean environment reduces order-dependent failures and makes reruns easier to interpret. Snapshots or persistence can help when deliberately carrying state, but introduce a state lifecycle to manage.
- Limit setup to what tests exercise. Provisioning fewer resources keeps the test setup simpler and reduces unrelated failure points.
- Account for container startup. Docker daemon availability, socket access, and host/container networking can determine whether services such as Lambda or ECS can run in a test job.
- Pin versions for repeatability. A pinned image or controlled CLI version helps keep local and CI environments aligned. Update intentionally and review changes to service coverage.
- Retain evidence on failure. Export emulator logs and test reports before the ephemeral job ends.
- Review subscription requirements. LocalStack’s licensing page states that, as of March 23, 2026, Base, Ultimate, and Enterprise are commercial subscriptions and Hobby is for non-commercial use. Plan requirements and feature access can change; verify the current plan matrix and token status for your intended workload. LocalStack plans
10. Troubleshooting
| Symptom | Likely cause | What to check or change |
|---|---|---|
| The CLI cannot start the environment. | Docker is stopped or the CLI is not authenticated. | Confirm the Docker daemon is running, authenticate with the required Auth Token, and review the startup output. |
| The SDK times out or cannot connect. | The client uses the wrong endpoint or a hostname unreachable from its runtime. | Check the endpoint configured for the test client. If tests run in a container, test name resolution and network reachability from that container. |
| A command or API operation fails after the service starts. | The test may use an API or behavior not covered by the emulator configuration. | Check current LocalStack coverage for the exact service and operation, and inspect the emulator logs for the failing request. |
| Resources appear to be missing or tests pass only in a certain order. | Tests share state or setup is not repeatable. | Start from clean state, create required resources as part of test setup, use deterministic initial data, and avoid reliance on a previous job or test. |
| A service that launches containers fails in CI. | The runner lacks Docker daemon or socket access, or its networking differs from local development. | Check runner permissions, Docker availability, socket access, and host/container networking. Review the service-specific LocalStack and provider guidance. |
| GitHub Actions cannot run the selected workload. | The runner operating system or architecture may not support the required LocalStack workflow directly. | Consult the current GitHub Actions guide. In particular, account for its Windows runner limitation and the possible QEMU requirement and slower builds for arm64 Lambda emulation. |
| CI failures are hard to diagnose after a job ends. | Logs or reports were not exported before ephemeral infrastructure shut down. | Configure artifact and log export to run on failure as well as success. |
| A feature works for one team member but not another. | CLI, container image, configuration, token status, or plan access differs. | Align versions and configuration, and check the current LocalStack plan matrix and Auth Token status for the feature. |
11. Or skip the browser setup
For website screenshots that are part of a development workflow, ScreenshotNeo provides a screenshot API and MCP server. One GET request returns a screenshot or PDF. It is separate from AWS and LocalStack testing; use it when your workflow needs to capture a web page.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
See the ScreenshotNeo API documentation for request options. Cookie banners, popups, and chat widgets are removed before the shot. Bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Learn about ScreenshotNeo.
Sign up for 1,000 free screenshots a month, no card required.
FAQ
Does LocalStack require AWS credentials?
The local client still needs whatever configuration its SDK or tooling requires, but use test-only settings and a LocalStack endpoint. Do not point production credentials or configuration at a local test environment.
Can a LocalStack test prove the application will work in production AWS?
No. It checks the interactions exercised against emulated services. Validate production-specific behavior against AWS when that behavior matters.
Should CI reuse a LocalStack environment between jobs?
Usually, start each independent job with clean state. Use snapshots or persistence only when carrying state forward is a deliberate requirement.
Where do I check whether a particular AWS API is supported?
Check LocalStack’s current service coverage and the documentation for the specific service and API operation used by your application.


