Lambda is the glue and often the backbone of AWS architectures, from APIs to file processing and automation.
A Lambda function is code plus configuration that AWS runs on demand. You write a handler, for Python def handler(event, context), where event is a dict describing what happened (an HTTP request, an S3 upload, a batch of SQS messages) and context carries metadata such as the remaining time.
Configuration that matters:
- Runtime (
python3.13,nodejs22.x,java21and others) or a container image up to 10 GB. - Memory from 128 MB to 10,240 MB; CPU scales with it, so more memory often makes functions faster and no more expensive.
- Timeout up to 15 minutes. Long jobs belong elsewhere (Step Functions, ECS).
- Execution role for AWS permissions, and environment variables for configuration.
- Architecture:
arm64(Graviton) is usually cheaper per GB-second.
Invocation models: synchronous (API Gateway, function URLs, direct invoke; the caller waits), asynchronous (S3, SNS, EventBridge; Lambda queues the event and retries failures twice), and event source mappings where Lambda polls SQS, Kinesis or DynamoDB Streams and invokes with batches.
Each concurrent request runs in its own execution environment. Code outside the handler runs once per environment (on a cold start) and is reused by later warm invocations, so create SDK clients and load config there, but never keep request-specific state in globals.
Logs from print or logging go to CloudWatch Logs automatically. Deploy with the CLI, SAM, CDK or Terraform:
zip fn.zip app.py
aws lambda create-function --function-name hello --runtime python3.13 \
--architectures arm64 --handler app.handler --zip-file fileb://fn.zip \
--role arn:aws:iam::111122223333:role/orders-fnExample
# app.py
import json
INVOCATIONS = 0 # module scope: survives between warm invocations
def handler(event, context):
global INVOCATIONS
INVOCATIONS += 1
name = (event.get("queryStringParameters") or {}).get("name", "world")
return {
"statusCode": 200,
"headers": {"content-type": "application/json"},
"body": json.dumps({"hello": name, "invocation": INVOCATIONS}),
}
if __name__ == "__main__": # quick local test
print(handler({"queryStringParameters": {"name": "Ada"}}, None)["body"])
# {"hello": "Ada", "invocation": 1}
# aws lambda invoke --function-name hello --cli-binary-format raw-in-base64-out \
# --payload '{"queryStringParameters": {"name": "Ada"}}' out.jsonRemember
- Handler(event, context); the event's shape depends on the trigger
- Memory also sets CPU; timeout max is 15 minutes
- Init code outside the handler runs once per execution environment
- Sync, async and polled (event source mapping) invocation behave differently
Watch out for
- Keeping per-request data in global variables, which leaks into later invocations on a warm environment.