Hands-On: Deploy Your First Lambda Function
What You Will Build
A Node.js function deployed two ways — first through the console to see the moving parts, then via the AWS CLI the way you'd script it in CI — exposed to the internet with a function URL and debugged through CloudWatch logs.
Step 1 — Create the Function in the Console
- Go to Lambda → Create function → Author from scratch.
- Function name:
hello-api. - Runtime: Node.js 22.x. Architecture: arm64 (cheaper, no downside for JS).
- Under Permissions, keep Create a new role with basic Lambda permissions — this role lets the function write logs and nothing else.
- Click Create function.
Step 2 — Write the Code
The console opens an inline editor on index.mjs. Replace its contents:
export const handler = async (event) => {
const name = event.queryStringParameters?.name ?? 'world';
return {
statusCode: 200,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
message: `Hello, ${name}`,
requestId: event.requestContext?.requestId,
}),
};
};
Click Deploy (the code isn't live until you do — a common gotcha).
Step 3 — Test from the Console
Open the Test tab, create an event named basic with this payload, and click Test:
{
"queryStringParameters": { "name": "console" }
}
You should see a 200 response, plus the duration and billed duration — my cold start was around 120 ms, warm invocations under 2 ms.
Step 4 — Add a Function URL
A function URL gives you a public HTTPS endpoint with zero API Gateway setup:
- Configuration → Function URL → Create function URL.
- Auth type:
NONE(public — fine for this exercise, useAWS_IAMfor anything real). - Save, and copy the URL.
curl "https://YOUR_URL_ID.lambda-url.us-east-1.on.aws/?name=curl"
You get the JSON response back. That's a live API with no servers, no port config, no process manager.
Step 5 — Redeploy the Same Function via the AWS CLI
Console clicking doesn't scale. Here's the same lifecycle scripted. First, package the code:
mkdir hello-api && cd hello-api
# create index.mjs with the handler code from Step 2
zip function.zip index.mjs
Update the existing function's code:
aws lambda update-function-code \
--function-name hello-api \
--zip-file fileb://function.zip
Or create a brand-new function from scratch. This needs an execution role — reuse the one the console made (find its ARN under Configuration → Permissions):
aws lambda create-function \
--function-name hello-api-cli \
--runtime nodejs22.x \
--architectures arm64 \
--handler index.handler \
--zip-file fileb://function.zip \
--role arn:aws:iam::123456789012:role/hello-api-role-abc123
Invoke it directly from the CLI without any URL:
aws lambda invoke \
--function-name hello-api-cli \
--payload '{"queryStringParameters":{"name":"cli"}}' \
--cli-binary-format raw-in-base64-out \
response.json
cat response.json
Step 6 — Read the Logs
Every console.log in your handler lands in CloudWatch under the log group /aws/lambda/hello-api. Three ways to read them:
Console: function page → Monitor → View CloudWatch logs → open the latest log stream.
CLI, tailing live (my default while debugging):
aws logs tail /aws/lambda/hello-api --follow
CLI, searching past logs:
aws logs filter-log-events \
--log-group-name /aws/lambda/hello-api \
--filter-pattern "ERROR" \
--start-time $(($(date +%s) - 3600))000
Each invocation logs START, END, and a REPORT line. The REPORT line is the one to watch — it shows duration, billed duration, memory configured, and max memory used. If max memory used sits far below configured, you can lower the memory setting and pay less.
Step 7 — Break It on Purpose
Throw an error to see the failure path:
export const handler = async (event) => {
throw new Error('something exploded');
};
Deploy, hit the function URL, and you get a 502 from the URL layer. The real stack trace is in CloudWatch — this is the habit to build: the HTTP response tells you almost nothing, the logs tell you everything.
Cleanup
aws lambda delete-function --function-name hello-api
aws lambda delete-function --function-name hello-api-cli
aws logs delete-log-group --log-group-name /aws/lambda/hello-api
Lambda itself costs nothing while idle, but the log groups persist until deleted.
Common Problems
| Symptom | Likely Cause |
|---|---|
| Changes not reflected | Forgot to click Deploy in the console editor |
Runtime.HandlerNotFound | Handler setting doesn't match file.exportName (here: index.handler) |
CLI invoke fails on payload | Missing --cli-binary-format raw-in-base64-out on AWS CLI v2 |
| Function URL returns 403 | Auth type is AWS_IAM but the request is unsigned |