Lambda
AWS Lambda runs your code in response to events, with no server to manage. You pay per invocation + execution time; cold starts add latency on the first call.
Node Lambda + API GW + IAM + observability
EXAMPLE
# 1) Minimal Node handler (Lambda function)
# handler.mjs
export const handler = async (event, context) => {
console.log('event:', JSON.stringify(event));
return {
statusCode: 200,
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ ok: true, requestId: context.awsRequestId }),
};
};
# Package + deploy via AWS CLI
zip function.zip handler.mjs
aws lambda create-function \
--function-name hello \
--runtime nodejs20.x \
--handler handler.handler \
--role arn:aws:iam::123456789012:role/lambda-basic-exec \
--zip-file fileb://function.zip \
--architectures arm64 \
--memory-size 256 \
--timeout 10
# Update code
aws lambda update-function-code --function-name hello --zip-file fileb://function.zip
# 2) Invoke
aws lambda invoke --function-name hello --payload '{"hi":"there"}' /tmp/out.json && cat /tmp/out.json
# 3) Wire to API Gateway HTTP API
aws apigatewayv2 create-api \
--name hello-api --protocol-type HTTP \
--target arn:aws:lambda:us-east-1:123456789012:function:hello
aws lambda add-permission \
--function-name hello \
--statement-id apigw \
--action lambda:InvokeFunction \
--principal apigateway.amazonaws.com \
--source-arn 'arn:aws:execute-api:us-east-1:123456789012:*/*'
# Now: GET https://<api-id>.execute-api.us-east-1.amazonaws.com/ → invokes hello
# 4) IAM role — start minimal, attach managed policy for CloudWatch Logs
aws iam create-role \
--role-name lambda-basic-exec \
--assume-role-policy-document '{
"Version":"2012-10-17",
"Statement":[{
"Effect":"Allow",
"Principal":{"Service":"lambda.amazonaws.com"},
"Action":"sts:AssumeRole"
}]
}'
aws iam attach-role-policy --role-name lambda-basic-exec \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
# Add per-service permissions as needed (read S3, write DynamoDB)
# 5) Common event sources
# API Gateway (HTTP / REST)
# S3 (object created/deleted)
# DynamoDB Streams (row change)
# SQS (messages)
# EventBridge (cron + custom events)
# Step Functions (workflow state)
# CloudFront (Edge — lighter cold start)
# SNS (pub/sub fanout)
# 6) Cold starts + tuning
# - Smaller bundle = faster cold start. Bundle (esbuild) + tree-shake.
# - arm64 + 512-1024 MB = best price/perf for most code.
# - Reuse SDK clients OUTSIDE the handler — they survive between warm calls.
import { S3Client } from '@aws-sdk/client-s3';
const s3 = new S3Client({}); // module-level — reused
export const handler = async (event) => {
await s3.send(new GetObjectCommand({ /* ... */ }));
};
# - Provisioned Concurrency keeps containers warm (extra cost, near-zero cold start)
aws lambda put-provisioned-concurrency-config --function-name hello --qualifier 1 --provisioned-concurrent-executions 5
# 7) Environment variables
aws lambda update-function-configuration \
--function-name hello \
--environment 'Variables={NODE_ENV=production,LOG_LEVEL=info}'
# 8) Secrets
# - Don't put secrets in env vars (they show in console)
# - Use AWS Secrets Manager / Parameter Store, fetch at cold start, cache in module scope
import { SSMClient, GetParameterCommand } from '@aws-sdk/client-ssm';
const ssm = new SSMClient({});
let dbUrl;
async function getDbUrl() {
if (!dbUrl) {
const r = await ssm.send(new GetParameterCommand({
Name: '/prod/app/db_url', WithDecryption: true,
}));
dbUrl = r.Parameter.Value;
}
return dbUrl;
}
# 9) Observability
# - Logs auto-stream to CloudWatch Logs (/aws/lambda/<name>)
# - Structured logging — log JSON, query via CloudWatch Logs Insights
# - X-Ray tracing — add AWSXRayDaemonWriteAccess policy + AWS_XRAY_DAEMON_ADDRESS env
# - Lambda Powertools — typed logging, metrics, tracing for Node/Python/TS
# 10) Local dev + test
# - AWS SAM (sam local invoke), Serverless Framework, AWS CDK, SST
# - Run unit tests like normal Node code; integration tests with LocalStack
# 11) Anti-patterns
# - Massive monolithic Lambdas — split by route, share libs
# - Long-running Lambdas (>1 min on hot path) — move to ECS/Fargate or Step Functions
# - DB connection per invocation — use RDS Proxy or short-lived HTTP databases (Aurora Data API, DynamoDB)
# - Sync invocations chained — fan-out via EventBridge or SQS
# 12) Cost ballpark
# 1M invocations free per month
# After that: $0.20 per 1M + GB-second time
# 100ms @ 512MB = ~5e-6 per invocation
Why it matters
Pin module-scope SDK clients + DB connections; secrets via Parameter Store / Secrets Manager, never env vars. Cold-start work happens once per container; design Lambdas like “init once, handle many.”
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
# Serverless compute. Bring code, AWS runs it on every event.
export const handler = async (event) => ({ statusCode: 200, body: 'OK' });
Try it Yourself »
Exercise
Invoke a Lambda function via CLI.
aws lambda
--function-name fn out.json
Six letters.
Discussion
Loading…