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
For further actions, you may consider blocking this person and/or reporting abuse
