VOOZH about

URL: https://dev.to/boris9027/a-practical-guide-to-local-lambda-debugging-using-sam-cli-with-terraform-and-vs-code-5fcm

⇱ A Practical Guide to Local Lambda Debugging: Using SAM CLI with Terraform and VS Code - DEV Community


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 ps should 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_object call will fail locally unless you have real AWS credentials that can reach the S3 bucket. For offline-only testing, you'd mock boto3 (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)

  1. Open lambda_function/lambda_function.py
  2. Click the gutter to the left of line 11 (current_timestamp = ...) to set a breakpoint (red dot)
  3. Press F5 or go to Run → Start Debugging
  4. Select "lambda_function:lambda_function.lambda_handler (python3.13)"
  5. 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:

  1. Set your breakpoints in lambda_function.py
  2. Press F5 and select "Attach to SAM Local"
  3. 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