Run code without managing servers: deploy a Lambda function, invoke it, trigger it from events and schedules, expose it over HTTP with API Gateway, share code with layers, manage versions and aliases, and handle cold starts.
A Lambda function is code that runs on demand — AWS spins up the environment, runs your function, then tears it down. Why: there is no server to provision, patch, or pay for while idle; you pay per millisecond of execution. Perfect for event-driven work and APIs with uneven traffic.
List your functions
aws lambda list-functions --query 'Functions[].FunctionName'A function needs code (zipped), a runtime (e.g. Python, Node.js), a handler (the entry-point function), and an execution role (its IAM permissions). Why the role: the function runs AS that role, so it gets temporary credentials to touch other AWS services — no keys in code.
A tiny Python handler — save this as handler.py
def handler(event, context):
name = event.get("name", "world")
return {"message": f"Hello, {name}!"}Zip it up for upload
zip function.zip handler.pyCreate the function (AppServerRole from the IAM lesson grants permissions)
aws lambda create-function --function-name hello \
--runtime python3.12 --handler handler.handler \
--role arn:aws:iam::111122223333:role/AppServerRole \
--zip-file fileb://function.zipInvoke it with an input event and read the result
aws lambda invoke --function-name hello \
--payload '{"name":"Alice"}' --cli-binary-format raw-in-base64-out \
out.json && cat out.jsonLambda functions are usually run by events, not by you. Why event-driven: a file lands in S3, a row changes in DynamoDB, a message hits a queue, a schedule fires — and your function runs in response. You wire a trigger by giving the source permission and (for some) an event-source mapping.
Let S3 invoke the function, then have a bucket call it on new uploads
aws lambda add-permission --function-name hello \
--statement-id s3invoke --action lambda:InvokeFunction \
--principal s3.amazonaws.com \
--source-arn arn:aws:s3:::my-app-uploads-7f3kFor streams/queues you create an event-source mapping instead, e.g.
aws lambda create-event-source-mapping --function-name hello \
--event-source-arn arn:aws:dynamodb:us-east-1:111122223333:table/Orders/stream/2024 \
--starting-position LATESTTo run a function on a timer (a cron job without a server), point an EventBridge schedule at it. Why: nightly cleanups, hourly report generation, periodic health pings — all without keeping a server running just to wait for the clock.
Fire every day at 02:00 UTC (reuses the EventBridge rule pattern)
aws events put-rule --name nightly-hello \
--schedule-expression 'cron(0 2 * * ? *)'aws lambda add-permission --function-name hello \
--statement-id eventbridge --action lambda:InvokeFunction \
--principal events.amazonaws.comaws events put-targets --rule nightly-hello \
--targets 'Id=1,Arn=arn:aws:lambda:us-east-1:111122223333:function:hello'API Gateway turns a Lambda function into a real HTTP endpoint clients can call. Why: it is how you build a serverless web API — the gateway handles routing, the function handles logic, and you pay only per request. An HTTP API is the simplest, cheapest flavor.
Create an HTTP API wired straight to the Lambda function
aws apigatewayv2 create-api \
--name hello-api --protocol-type HTTP \
--target arn:aws:lambda:us-east-1:111122223333:function:helloAllow API Gateway to invoke the function
aws lambda add-permission --function-name hello \
--statement-id apigw --action lambda:InvokeFunction \
--principal apigateway.amazonaws.comThe create-api output prints an https://...execute-api... URL to curl.
Lambda supports many languages out of the box, but for anything else (Rust, a specific PHP, a custom binary) you provide your own runtime. Why: you package a bootstrap that follows Lambda's runtime API, usually via the "provided.al2023" base, and run literally any language.
Use the OS-only base runtime; your zip must contain a "bootstrap" file
aws lambda create-function --function-name custom-fn \
--runtime provided.al2023 --handler bootstrap \
--role arn:aws:iam::111122223333:role/AppServerRole \
--zip-file fileb://custom.zipOften easier as a container image (see the Containers lesson): --package-type Image --code ImageUri=...
Publishing a version freezes the current code as an immutable, numbered snapshot. An alias is a named pointer (like "prod") to a version. Why: you point "prod" at v3, deploy v4, test it, then move the alias — and you can shift traffic gradually or roll back instantly by repointing the alias.
Freeze the current code as a numbered version
VER=$(aws lambda publish-version --function-name hello \
--query 'Version' --output text)Create/point a "prod" alias at it
aws lambda create-alias --function-name hello \
--name prod --function-version $VERCanary: send 10% of "prod" traffic to a newer version
aws lambda update-alias --function-name hello --name prod \
--function-version $VER \
--routing-config 'AdditionalVersionWeights={"5"=0.1}'When a function hasn't run recently, Lambda must set up a fresh environment first — a "cold start" of tens to hundreds of milliseconds. Limits to know: max 15-minute runtime, up to 10 GB memory (more memory = more CPU), and a deployment-size cap. Why: provisioned concurrency keeps environments warm for latency-sensitive APIs.
Give the function more memory (and thus more CPU) and a 30s timeout
aws lambda update-function-configuration --function-name hello \
--memory-size 1024 --timeout 30Keep 5 environments pre-warmed to avoid cold starts on the prod alias
aws lambda put-provisioned-concurrency-config --function-name hello \
--qualifier prod --provisioned-concurrent-executions 5Lambda@Edge runs functions at CloudFront edge locations, close to users, to modify requests and responses in flight. Why: rewrite URLs, add security headers, do auth checks, or A/B test — all at the edge before traffic reaches your origin. Edge functions must live in us-east-1 and be attached to a distribution.
Edge functions are published as versions and associated with a CloudFront behavior. Create and publish in us-east-1:
aws lambda create-function --function-name edge-headers \
--region us-east-1 \
--runtime nodejs20.x --handler index.handler \
--role arn:aws:iam::111122223333:role/AppServerRole \
--zip-file fileb://edge.zipaws lambda publish-version --function-name edge-headers --region us-east-1Then attach the version ARN to a CloudFront cache behavior event (viewer-request / origin-response) in the distribution config.