SAM Local Testing

Earn 25 points (50 with Pro) in two steps

  1. ① Read through the lesson — each section gets a ✓ as you scroll through it.
  2. ② When every section has a ✓, tap Complete lesson.

0 of 11 read · keep scrolling

✦ See fewer ads and earn double points — 50 a lesson instead of 25 — with Pro

SAM Local Testing: A Deep Dive into Serverless Development

Introduction: Why Local Testing Matters in Serverless

When you start building applications with AWS Serverless Application Model (SAM), you are essentially shifting your development paradigm from traditional server-based architectures to event-driven, managed services. In a traditional environment, you might have a local staging server that mimics production. In serverless, however, your "server" is an abstraction provided by AWS services like Lambda, API Gateway, and DynamoDB. Testing these locally presents a unique challenge: how do you verify your code without deploying it to the cloud every single time?

This is where SAM Local testing enters the picture. The AWS SAM CLI provides a suite of tools that allow you to emulate the AWS environment on your local machine. By using Docker containers that mimic the execution environment of AWS Lambda, you can run your code, debug it, and inspect its behavior before you ever trigger a deployment. This workflow is critical for maintaining productivity, reducing costs associated with repeated deployments, and shortening the feedback loop between writing code and verifying functionality.

Without a local testing strategy, developers often fall into the "deploy-test-fix" cycle. This involves pushing code to the cloud, waiting for the deployment to complete, checking logs in CloudWatch, and then repeating the process. This cycle is notoriously slow and frustrating. By mastering SAM local testing, you reclaim control over your development time and build a more reliable, test-driven development process.


Not read yet

Understanding the SAM CLI Architecture

The AWS SAM CLI is built around the concept of "emulation." It does not recreate the entire AWS ecosystem on your laptop; rather, it uses Docker to create an environment that matches the runtime settings of your Lambda functions. When you invoke a function locally, SAM pulls the appropriate Docker image (e.g., Python 3.9, Node.js 18, Java 11) and runs your code inside that container, injecting mock event data as if it were coming from an actual AWS trigger.

Key Components of SAM Local

To effectively use SAM for local testing, you need to understand three primary commands:

  1. sam local invoke: Executes a single Lambda function locally with a specific event payload.
  2. sam local start-api: Starts a local web server that mimics API Gateway, allowing you to trigger functions via HTTP requests.
  3. sam local start-lambda: Starts a local endpoint that mimics the AWS Lambda service, which can be used to test service-to-service communication.

Callout: The "Local vs. Cloud" Distinction While SAM local is excellent for testing logic, input validation, and code structure, it is not a perfect mirror of the cloud. Local testing cannot replicate IAM permissions, service quotas, or real-world network latency. Always treat local testing as the first line of defense, but never skip integration testing in a real AWS environment before going to production.


Not read yet

Setting Up Your Development Environment

Before you can run local tests, you must ensure your workstation is configured correctly. The primary requirement for SAM local testing is Docker. Because SAM uses containers to emulate the Lambda execution environment, the Docker daemon must be running and accessible by the SAM CLI.

Prerequisites

  • AWS SAM CLI: Installed and configured.
  • Docker Desktop (or Docker Engine): Running on your machine.
  • AWS CLI: Configured with valid credentials (even if you are only running locally, SAM often needs credentials to resolve environment variables or access local configuration).

Verification Steps

To verify that your installation is ready, open your terminal and run the following commands:

  1. Check SAM CLI version: sam --version
  2. Check Docker availability: docker ps

If these commands return successfully, your environment is ready. If Docker fails, ensure your Docker Desktop application is fully launched and your user account has the necessary permissions to interact with the Docker socket.


Not read yet

Mastering sam local invoke

sam local invoke is the bread and butter of unit testing your Lambda functions. It allows you to pass a JSON file representing an event (like an S3 upload or a DynamoDB change) to your function and see the output immediately.

The Workflow

  1. Write your function code: Create your Lambda handler.
  2. Create an event file: Create a events/event.json file containing the mock data you expect your function to process.
  3. Run the invoke command: Execute sam local invoke FunctionName -e events/event.json.

Practical Example: Processing an API Gateway Event

Imagine you have a function that processes a POST request. Your events/event.json should look like a standard API Gateway proxy request:

{
  "resource": "/my-path",
  "path": "/my-path",
  "httpMethod": "POST",
  "body": "{\"name\": \"John Doe\", \"action\": \"create\"}",
  "headers": {
    "Content-Type": "application/json"
  }
}

Now, run the command: sam local invoke MyFunction --event events/event.json

SAM will pull the necessary Docker image, mount your code directory into the container, and execute the function. You will see the function's logs stream to your terminal, followed by the JSON output returned by your code.

Tip: Debugging with Environment Variables Often, your code relies on environment variables (e.g., TABLE_NAME, DEBUG_MODE). You can pass these to sam local invoke using the --env-vars flag. Create a JSON file (e.g., env.json) to define these variables and use the command: sam local invoke MyFunction -e events/event.json --env-vars env.json.


Not read yet

Simulating APIs with sam local start-api

Testing individual functions is great, but testing the interaction between your API Gateway routes and your Lambda functions is better. The sam local start-api command creates a local HTTP server that routes requests to your Lambda functions based on your template.yaml configuration.

How it works

When you run sam local start-api, SAM reads your template.yaml file, parses the AWS::Serverless::Function and Events properties, and maps them to local ports. If your API is defined on port 3000, you can point your browser or tools like Postman or curl to http://localhost:3000/.

Step-by-Step Implementation

  1. Ensure your template.yaml defines an Api event source for your function.
  2. Run sam local start-api in your project root.
  3. Once the server is running, open a new terminal window.
  4. Send a request: curl -X POST http://localhost:3000/my-path -d '{"data": "test"}'.

This allows you to test your middleware, validation logic, and response formatting in a way that feels very similar to hitting a live API.

Callout: Performance and Hot Reloading One of the most powerful features of sam local start-api is its ability to handle code changes. If you are using interpreted languages like Python or Node.js, SAM will automatically re-mount your code changes on each request if you are running in a standard configuration. This enables a "hot-reloading" experience where you change a line of code, save the file, and immediately hit the API to see the results.


Not read yet

Advanced Testing Techniques

As your application grows, simple invocation is not enough. You need to handle complexities like secrets, layers, and service emulation.

Testing with Lambda Layers

If your project uses Lambda Layers to share code or dependencies, SAM handles this by mounting the layer directory into the container alongside your function code. You don't need to do anything special; just ensure your template.yaml references the layer correctly. SAM will look for the layer files in your local project directory and make them available to the runtime.

Mocking AWS Services

SAM Local does not automatically mock services like DynamoDB or SQS. If your code calls boto3.client('dynamodb'), it will attempt to reach the actual AWS DynamoDB endpoint. To test locally without hitting AWS, you have two primary options:

  1. Use Moto: A Python library that mocks AWS services. You can use it within your unit tests to intercept calls to AWS.
  2. Use LocalStack: A popular open-source tool that provides a local cloud stack. You can configure your SAM functions to point to the LocalStack endpoint instead of the real AWS endpoint by setting the ENDPOINT_OVERRIDE environment variable.

Handling IAM Permissions

A common pitfall is assuming that because your code runs locally, it has the same permissions as your deployed function. This is false. When running locally, SAM uses your local machine's AWS credentials (usually defined in ~/.aws/credentials). If your local user has administrator access, your local function will have administrator access, even if the actual Lambda role is restricted. Always use a least-privilege policy for your local development profile to catch permission issues early.


Not read yet

Best Practices for SAM Local Testing

1. Maintain a Dedicated Events Library

Do not just keep one event.json file. Create an events/ folder in your project and store different types of events there. For example:

  • events/api_post_request.json
  • events/s3_upload_event.json
  • events/sqs_message.json This ensures you can test various code paths without manually editing a single file every time.

2. Use Unit Testing Frameworks

SAM Local is an integration/emulation tool, not a substitute for proper unit tests. Use frameworks like pytest (for Python) or Jest (for Node.js) to test your business logic in isolation. Use SAM Local to verify that the "glue" code (the event parsing and the response construction) works correctly.

3. Keep Docker Images Updated

SAM periodically releases new Docker images to match updated Lambda runtimes. Run sam build --use-container periodically to ensure your local environment is pulling the latest images, which contain security patches and updated library environments.

4. Manage Environment Variables Securely

Never commit your env.json or aws-credentials files to version control. Use a .gitignore file to exclude these files. If you need to share environment structures with your team, use a template file like env.json.template and instruct team members to fill in their own values.


Not read yet

Common Pitfalls and Troubleshooting

"My function is timing out locally!"

If your function times out locally, it is often due to the overhead of starting the Docker container. Increase the Timeout property in your template.yaml for testing, or check if your function is trying to establish a connection to a resource (like a database) that isn't accessible from your local network.

"My changes aren't reflecting!"

If you make a change to your code but the output remains the same, you likely haven't rebuilt your project. SAM builds your code into a .aws-sam directory. Whenever you change your code, run sam build before running sam local invoke. If you are using the --use-container flag, this is even more critical as it ensures the build artifacts are compatible with the execution environment.

"The local endpoint is blocked!"

Ensure your firewall or antivirus software isn't blocking the ports SAM uses (default 3000). Also, ensure that no other service on your machine is using the same port. You can change the port for sam local start-api using the -p flag: sam local start-api -p 8080.


Not read yet

Comparison Table: SAM Local vs. Unit Testing vs. Cloud Testing

Feature SAM Local Unit Testing Cloud Testing
Speed Medium Very Fast Slow
Accuracy High (Emulated) Low (Logic only) Perfect (Actual)
Infrastructure Minimal (Docker) None Full AWS
Cost Free Free Incurring
Best For Integration/Event Flow Logic/Business Rules Production Readiness

Step-by-Step: Testing a Full Workflow

To put everything together, let's walk through testing a simple "Create User" Lambda.

  1. Initialize the template: Use sam init to create a standard project structure.
  2. Define the resource: In template.yaml, add an AWS::Serverless::Function with an Api event.
  3. Write the handler: Write the logic to parse the body and save to a mock database.
  4. Build the project: Run sam build.
  5. Run the API: Run sam local start-api.
  6. Test the endpoint: Use curl to send a POST request to localhost:3000.
  7. Inspect logs: Observe the standard output in your terminal where sam local start-api is running.
  8. Iterate: If the code fails, update the handler, run sam build again, and retry the curl command.

This cycle is the backbone of efficient serverless development. By keeping the feedback loop tight, you can experiment with different library versions, event structures, and logic flow without the overhead of the AWS Console.


Not read yet

Security Considerations in Local Testing

While testing locally, you are essentially running code in a container that has access to your local machine's credentials. It is vital to recognize that if your code is malicious or poorly written, it could potentially access your local AWS configuration files.

  • Restrict IAM Policies: Never use your root account credentials for local development. Use an IAM user with minimal permissions.
  • Avoid Hardcoding Secrets: Even in local testing, do not hardcode secrets in your source code. Use environment variables and load them via the env.json file.
  • Network Isolation: Be aware that if you are connected to a corporate VPN, your local Lambda container might have access to internal resources that your production Lambda would not. Ensure your tests reflect the intended network environment.

FAQ: Frequently Asked Questions

Can I debug my code with breakpoints while using SAM Local?

Yes. You can use the --debug-port flag with sam local invoke or sam local start-api. This opens a port that your IDE (like VS Code or PyCharm) can attach to, allowing you to set breakpoints, inspect variables, and step through your code just as if it were running on your local machine.

Does SAM Local support all AWS services?

No. SAM Local is primarily designed for Lambda, API Gateway, and SQS/SNS local emulation. For services like Cognito, AppSync, or EventBridge, you might need to use third-party mocks or write custom logic to emulate those events.

Is sam local the same as sam build?

No. sam build prepares your code and dependencies by creating a deployment package. sam local is the execution engine that uses those packages to run your code. You must run sam build before running sam local.

Can I run SAM Local on Windows?

Yes, SAM CLI supports Windows, but you must have Docker Desktop installed with WSL 2 (Windows Subsystem for Linux) integration enabled. This is the recommended way to ensure compatibility between the Linux-based Lambda environment and your Windows development environment.


Not read yet

Key Takeaways

  1. Shorten the Feedback Loop: The primary goal of SAM Local testing is to avoid the time-consuming deploy-test-fix cycle by emulating the AWS runtime environment on your local machine.
  2. Leverage Docker: SAM relies on Docker to create a consistent execution environment. A healthy Docker installation is the foundation of a successful local testing workflow.
  3. Use the Right Tool for the Job: Use sam local invoke for isolated function testing, sam local start-api for integration testing of API routes, and traditional unit testing frameworks for business logic.
  4. Maintain an Event Library: Build a robust collection of JSON event files. This allows you to quickly simulate different triggers, such as API requests, S3 uploads, or database stream changes, without manual configuration.
  5. Debug Effectively: Utilize the --debug-port flag to attach your IDE debugger to the Lambda container, which provides a significantly better experience than relying solely on print statements.
  6. Mind the Differences: Remember that local testing is an emulation, not a mirror. Always perform final integration tests in a real AWS environment to account for IAM roles, service quotas, and network configuration.
  7. Security First: Even during development, adhere to the principle of least privilege by using scoped AWS credentials and never committing sensitive information to your local configuration files.

By internalizing these practices, you move from a reactive developer waiting on cloud deployments to a proactive engineer who can verify, debug, and iterate on complex serverless applications with confidence and speed. The transition to serverless does not mean you have to sacrifice the immediate feedback of local development; you simply need to adapt your tooling to the new paradigm of container-based execution.

Not read yet

Each section gets a ✓ as you scroll through it. Tap the button to jump to the next one.