Automate Your Serverless Tests with GitHub Actions and LocalStack
Tired of forgetting to run tests before you push? In this tutorial, you'll learn how to automate your serverless integration tests using GitHub Actions and LocalStack. We'll spin up your stack in CI, run real tests against S3, Lambda, SQS, and DynamoDB, and make sure your pipeline catches bugs before they hit production.

You wrote some tests. You ran them locally. You even watched DynamoDB get populated and felt like a responsible developer. If you followed along with the last post, you saw how to verify your S3-to-DynamoDB pipeline using real integration tests, all running on LocalStack without touching the actual cloud. But let’s be honest. Are you really going to run those tests every single time you make a change? Probably not.
That’s why we’re plugging those tests into a continuous integration (CI) pipeline. Now, every time you push code or open a pull request, your LocalStack-powered integration tests will run automatically. No skipped steps. No forgotten test runs. Just fast, consistent feedback. In this post, we’ll set up GitHub Actions to spin up LocalStack, deploy your CDK stack, and run your tests. If anything breaks, you’ll know about it before your coworkers do.
What You’re Setting Up
Here’s what we’ll cover:
- Creating a workflow file at
.github/workflows/test.yml
. - Using a LocalStack container as a service inside GitHub Actions.
- Deploying your CDK stack to LocalStack.
- Running your pytest integration tests just like you do locally.
What You’ll Need
Before we dive in, make sure you have:
- Integration tests written using pytest and boto3 from the previous post
- A working
requirements.txt
that includes your test dependencies. - A CDK stack that deploys cleanly with
cdklocal
. - A nice, hot pot of coffee (optional, but helpful).
GitHub Actions Workflow File
Here’s the workflow file we’re using to run tests against LocalStack in CI. It sets up Python and Node, installs your dependencies, spins up LocalStack, deploys your CDK stack, and runs your tests with pytest.
Create a new file at .github/workflows/ci.yml
and drop this in:
name: Test on LocalStack
on: push: branches: [ main ] # run on pushes to main pull_request: branches: [ main ] # run on PRs targeting main workflow_dispatch: # allow manual runs from the Actions tab
jobs: localstack-test: name: Deploy on LocalStack runs-on: ubuntu-latest
steps: # 1) Get your repo files onto the runner - name: Checkout code uses: actions/checkout@v4
# 2) Python for tests and boto3 - name: Set up Python uses: actions/setup-python@v4 with: python-version: '3.11'
# 3) Node for AWS CDK tooling - name: Set up Node uses: actions/setup-node@v4 with: node-version: '20'
# 4) Install your app and test dependencies - name: Install dependencies run: | python -m pip install --upgrade pip pip install -r requirements.txt
# 5) Install CDK and CDKLocal, confirm cdklocal is available - name: Install CDK and CDKLocal run: | npm install -g aws-cdk-local aws-cdk cdklocal --version
# 6) Start LocalStack with Pro features enabled - name: Start LocalStack uses: LocalStack/setup-localstack@main with: image-tag: 'latest' # pull the latest LocalStack image install-awslocal: true # also install the awslocal helper use-pro: true # turn on Pro features env: LOCALSTACK_AUTH_TOKEN: ${{ secrets.LOCALSTACK_AUTH_TOKEN }}
# 7) Deploy your CDK app into LocalStack - name: Deploy CDK stack run: | cdklocal bootstrap # one-time infra bootstrap in LocalStack cdklocal deploy --require-approval never
# 8) Run your tests against the deployed stack - name: Run tests env: AWS_DEFAULT_REGION: us-east-1 # dummy creds are fine with LocalStack AWS_REGION: us-east-1 AWS_ACCESS_KEY_ID: test AWS_SECRET_ACCESS_KEY: test # Optional, helps boto3 find LocalStack if your tests read this env: # AWS_ENDPOINT_URL: http://localhost:4566 run: | pip3 install boto3 pytest pytest --disable-warnings
What’s Happening in This Workflow
Here’s a breakdown of what each step is doing:
- Step 1: Check out your code so we’re not testing an empty directory.
- Step 2: Set up Python because pytest and boto3 need it.
- Step 3: Set up Node because our flavor of AWS CDK is a TypeScript party under the hood.
- Step 4: Install dependencies so your app and test code can actually run.
- Step 5: Install CDK tools globally using npm and make sure cdklocal is available.
- Step 6: Start LocalStack using the official GitHub Action with Pro enabled.
- Step 7: Deploy your CDK stack using cdklocal, skipping approval prompts.
- Step 8: Run your tests using pytest, and disable warnings to keep the logs readable.
This workflow mirrors your local dev environment and catches issues as early as possible. If something breaks, the workflow fails, and you’ll know exactly where it fell apart.
Tips and Gotchas
Here are a few extra things worth knowing as you level up your local testing setup:
The setup-localstack
action includes built-in health checks, so you don’t need to manually wait for services to be ready. That said, if your stack creates a lot of resources or triggers complex Lambdas, you might want to add a short pause before running tests, just to give everything time to settle.
You’re already using --require-approval never
to avoid CDK approval prompts. Good. Keep doing that. If you expand your stack to include other services like SNS, Kinesis, or Secrets Manager, just add them to the SERVICES
variable when starting LocalStack.
Try running the workflow locally with act
or a test branch before pushing changes to main. CI is not the place to find out your indentation was off by two spaces.
You’re Now Testing Like You Mean It
With this setup, every commit and pull request runs your integration tests against a fully local AWS environment. You catch bugs early, build confidence in your infrastructure, and sleep better knowing that nothing surprising is hiding in staging.
Want to see it all in action?
Watch the companion video where we walk through this CI setup step by step: 👉🏾 Watch the CI walkthrough on YouTube
In the next post, we’ll dig into LocalStack Cloud Pods and show you how to save and restore your infrastructure state. This means faster bootstraps, repeatable environments, and one less reason to say “it worked on my machine.”
Until then, commit often, test early, and break things with confidence.