Skip to content
Get Started for Free

CI/CD

LocalStack works great in CI environments, allowing your integration tests to run incredibly fast and with no cloud costs. The setup differs slighty from local development in a few important ways:

  • Use a CI Auth Token, not your personal Developer token
  • Start LocalStack without a browser — Docker Compose, docker run, or CI helpers such as setup-localstack are common; lstk also works in CI when you set LOCALSTACK_AUTH_TOKEN and use --non-interactive (or rely on automatic non-interactive detection). LocalStack Desktop remains a local-only GUI.
  • Runs are often isolated per job — many pipelines start from an empty LocalStack instance for reproducible tests
  • Persistence in CI is supportedCloud Pods, snapshot-based persistence with a mounted volume, or localstack state export / localstack state import with artifacts or cache.

CI pipelines should use a dedicated CI Auth Token, not a developer token tied to a specific user.

  1. Go to the Auth Tokens page in the LocalStack Web Application
  2. Create a new CI Auth Token
  3. Add it as a secret in your CI provider (e.g., LOCALSTACK_AUTH_TOKEN)

See the Auth Token documentation for full details on token types and configuration.

The recommended approach is to start LocalStack as a service container or as a step using the official GitHub Action:

.github/workflows/integration-tests.yml
name: Integration Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Start LocalStack
uses: LocalStack/setup-localstack@v0.2.2
with:
image-tag: latest
install-awslocal: "true"
env:
LOCALSTACK_AUTH_TOKEN: ${{ secrets.LOCALSTACK_AUTH_TOKEN }}
- name: Run tests
run: |
# Your test commands here, e.g.:
pip install awscli-local
awslocal s3 mb s3://my-test-bucket
pytest tests/integration/

The setup-localstack action handles pulling the image, starting the container, and waiting for LocalStack to be ready.

After LocalStack starts, confirm the license is active:

Terminal window
curl -s http://localhost:4566/_localstack/info | jq '.is_license_activated'
# Should return: true
Local developmentCI/CD
CLIlstk or LocalStack CLIDocker Compose / docker run, or lstk --non-interactive
AuthBrowser login or stored tokenLOCALSTACK_AUTH_TOKEN env var
Token typeDeveloper tokenCI token
StateOptional persistenceOptional persistence (same mechanisms; typical pattern is a fresh instance per job)
StartupInteractive TUI (default lstk)Non-interactive (docker compose, docker run -d, lstk --non-interactive)

If you tear down the container at the end of a job, nothing is left on disk unless you save it — which is why many teams use a clean instance every time. When you do need to reuse infrastructure or data between pipeline runs or steps, CI is fully supported:

  • Cloud Pods — save and load snapshots; the setup-localstack action can load and save pods via state-backend: cloud-pods (see GitHub ActionsStore Localstack state).
  • Snapshot-based persistence — enable PERSISTENCE=1 and mount a volume so state survives container restarts on the same runner or workspace.
  • State export/import — run localstack state export and localstack state import and pass the file through your CI provider’s artifacts, cache, or attached storage (for example, see GitLab CIStore Localstack state).

Choose the approach that fits your runner model: for example, multi-job GitLab pipelines often need explicit state handoff because services do not carry between jobs.

LocalStack has dedicated integration guides for many CI providers:

See the full CI/CD integrations section for details.

Was this page helpful?