A practical guide to debugging Lambda functions locally using SAM CLI and VS Code — no more deploying just to test a print() statement.
What You'll Learn
- How to invoke a Lambda function locally from the command line
- How to spin up a local API that mirrors your API Gateway
- How to attach a debugger in VS Code and step through your code
- How to hit a deployed Lambda from your machine
The Project
Github repo
This repo deploys a simple serverless stack:
| Resource | Purpose |
|---|---|
| Lambda Function | Python function that writes a timestamp to S3 |
| S3 Bucket | Stores timestamp files |
| API Gateway (HTTP) | Exposes the Lambda at GET /timestamp
|
All infrastructure is defined in Terraform. The Lambda source lives in lambda_function/lambda_function.py:
import time
import boto3
import os
def lambda_handler(event, context):
"""
AWS Lambda function that stores current timestamp in S3.
"""
current_timestamp = int(time.time())
s3 = boto3.client("s3")
bucket_name = os.environ["S3_BUCKET_NAME"]
file_name = f"timestamp-{current_timestamp}.txt"
s3.put_object(Bucket=bucket_name, Key=file_name, Body=str(current_timestamp))
return {
"statusCode": 200,
"body": {
"message": "Timestamp saved successfully",
"timestamp": current_timestamp,
"file": file_name,
},
}
Prerequisites
Make sure these are installed and working before you start: Terraform, AWS SAM CLI, Docker, Python, VSCode. Verify everything is in place:
terraform version
sam --version
docker ps
python3 --version
Note:
docker psshould run without error. If Docker isn't running, SAM CLI will fail when trying to build or invoke locally.
Project File Map
Here's what matters for debugging:
.
├── main.tf # All Terraform infra (Lambda, S3, API Gateway, IAM)
├── lambda_function/
│ ├── lambda_function.py # Your Lambda handler
│ └── requirements.txt # Python dependencies
├── ev.json # Sample event payload for local invoke
├── .vscode/
│ └── launch.json # VS Code debug configurations
└── cli_helper.txt # Quick reference CLI commands
Method 1: Debugging with SAM CLI (Command Line)
SAM CLI can read your Terraform project directly using the --hook-name terraform flag. No SAM template needed.
Step 1 — Build
SAM needs to prepare a local build of your function (it resolves dependencies and packages the code):
sam build --hook-name terraform
You'll see output like:
Building codeuri: /Users/you/tf-sam-play-master/lambda_function runtime: python3.13
metadata: {} functions: my_lambda
Running PythonPipBuilder:ResolveDependencies
Running PythonPipBuilder:CopySource
Build Succeeded
Built Artifacts : .aws-sam-iacs/build
Built Template : .aws-sam-iacs/build/template.yaml
Tip: Re-run this every time you change your Python code or dependencies.
Step 2 — Invoke Locally with a Custom Event
The repo includes ev.json — a sample S3 event payload. You can use it to simulate an invocation:
sam local invoke --event ./ev.json --hook-name terraform --debug
-
--event ./ev.json— feeds the event payload to your handler -
--hook-name terraform— tells SAM to read from Terraform, not a SAM template -
--debug— prints verbose logs (Docker commands, environment, etc.)
Expected output:
{
"statusCode": 200,
"body": {
"message": "Timestamp saved successfully",
"timestamp": 1745232000,
"file": "timestamp-1745232000.txt"
}
}
Important: The
s3 put_objectcall will fail locally unless you have real AWS credentials that can reach the S3 bucket. For offline-only testing, you'd mockboto3(covered in the Troubleshooting section).
Step 3 — Run a Local API
If you want to test through the API Gateway path (not just direct invoke):
sam local start-api --hook-name terraform --debug
SAM starts a local HTTP server. You'll see:
Mounting my_lambda at http://127.0.0.1:3000/{path+}
You can now browse to the above endpoints to invoke your functions.
Running on http://127.0.0.1:3000 (Press CTRL+C to quit)
Now hit it from another terminal:
curl http://127.0.0.1:3000/timestamp
This is useful for verifying that the API Gateway integration is wired correctly and that event routing works.
Step 4 — Remote Invoke (Hit the Deployed Lambda)
Once you've deployed with terraform apply, you can invoke the live Lambda from your machine:
sam remote invoke my_lambda --stack-name terraform-2025 --event '{"test": "data"}'
This sends a real event to the deployed function in AWS. Useful for comparing local vs. remote behavior.
Method 2: Debugging in VS Code
Step 1 — Install the AWS Toolkit Extension
- Open VS Code
- Go to Extensions (
Cmd+Shift+X) - Search for AWS Toolkit and install it
This extension understands SAM projects and provides the aws-sam debug type.
Step 2 — Understand the Launch Config
The repo ships with .vscode/launch.json containing three configurations:
{
"version": "0.2.0",
"configurations": [
{
"type": "aws-sam",
"request": "direct-invoke",
"name": "lambda_function:lambda_function.lambda_handler (python3.13)",
"invokeTarget": {
"target": "code",
"projectRoot": "${workspaceFolder}/lambda_function",
"lambdaHandler": "lambda_function.lambda_handler"
},
"lambda": {
"runtime": "python3.13",
"payload": {
"json": {
"fake": "event"
}
},
"environmentVariables": {}
}
},
{
"name": "Attach to SAM Local",
"type": "debugpy",
"request": "attach",
"listen": {
"host": "127.0.0.1",
"port": 3000
},
"pathMappings": [
{
"localRoot": "${workspaceFolder}/lambda_function/lambda_function",
"remoteRoot": "/timestamp "
}
]
},
{
"name": "Python: Current File",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"justMyCode": true
}
]
}
Here's what each one does:
| Config Name | When to Use |
|---|---|
Direct Invoke (aws-sam) |
Quick one-click invoke. Builds and runs in Docker. |
Attach to SAM Local (debugpy) |
Start API from CLI, then attach debugger. Full breakpoints. |
| Python: Current File | Run the Python file directly (no Lambda context). |
Step 3 — Set a Breakpoint and Debug
Option A — Direct Invoke (quickest)
- Open
lambda_function/lambda_function.py - Click the gutter to the left of line 11 (
current_timestamp = ...) to set a breakpoint (red dot) - Press
F5or go to Run → Start Debugging - Select "lambda_function:lambda_function.lambda_handler (python3.13)"
- VS Code builds a Docker container, invokes the handler, and pauses at your breakpoint
You can now inspect event, context, and all local variables in the Variables panel.
Option B — Attach to a Running Local API
This is the most realistic debugging setup because it mirrors the full request flow:
Terminal 1 — Start SAM's local API with the debug port open:
sam local start-api --hook-name terraform --debug-port 3000
VS Code — Attach the debugger:
- Set your breakpoints in
lambda_function.py - Press
F5and select "Attach to SAM Local" - The debugger connects and waits
Terminal 2 — Trigger a request:
curl http://127.0.0.1:3000/timestamp
VS Code pauses execution at your breakpoints. Step through the handler line by line.
Step 4 — Customize the Event Payload
In the Direct Invoke config, change the payload to match a real event:
"payload": {
"json": {
"queryStringParameters": {
"key": "value"
},
"pathParameters": {},
"body": null
}
}
Or point it to a file:
"payload": {
"jsonPath": "${workspaceFolder}/ev.json"
}
Working with Events
Generate Sample Events with SAM
Don't hand-write event payloads. SAM can generate them for you:
# Generate an S3 Put event
sam local generate-event s3 put --bucket my-bucket --key my-key
# Generate an API Gateway HTTP API event (proxy integration)
sam local generate-event apigateway http-api-proxy --method GET --path timestamp
# Save to a file
sam local generate-event s3 put > my-event.json
Then use it:
sam local invoke --event my-event.json --hook-name terraform --debug
Top comments (1)
github.com/borisBarac/tf-sam-play