AWS Lambda runs your code without servers you manage. You upload a function, connect it to an event (an HTTP request, a file upload, a message in a queue, a schedule) and Lambda runs it whenever that event happens, scaling from zero to thousands of parallel copies and back. You pay only while it runs.
That simplicity hides a few concepts every Lambda developer needs. Here they are.
The handler
A Lambda function is a handler: a function that receives an event (the data that triggered it) and a context (runtime information). In Python:
import json
def handler(event, context):
name = event.get("name", "world")
return {"statusCode": 200, "body": json.dumps({"hello": name})}
Lambda supports Node.js, Python, Java, .NET, Ruby, and custom runtimes (Go, Rust and others) through the OS-only runtimes, as well as container images up to 10 GB.
Triggers and invocation types
| Type | Examples | What happens on error |
|---|---|---|
| Synchronous | API Gateway, ALB, direct invoke, Cognito triggers | The caller gets the error and decides whether to retry |
| Asynchronous | S3 events, SNS, EventBridge | Lambda retries twice, then sends to a failure destination or dead-letter queue if configured |
| Poll-based (event source mapping) | SQS, Kinesis, DynamoDB Streams, Kafka | Lambda polls and retries the batch; failures can block the stream or return to the queue |
Knowing which model your trigger uses tells you where retries come from and why a function might run more than once.
Permissions: the execution role
Each function has an execution role, an IAM role that Lambda assumes when running your code. If the function writes to DynamoDB, the role needs dynamodb:PutItem on that table. It also needs permission to write logs to CloudWatch (the AWSLambdaBasicExecutionRole managed policy covers that).
Separately, a resource-based policy on the function controls who may invoke it, for example allowing S3 or API Gateway to call it. Two policies, two directions.
Memory, CPU and timeout
- Memory ranges from 128 MB to 10,240 MB, and CPU scales with it. More memory often makes functions faster and sometimes cheaper overall, because you pay for duration. Measure with a tool like AWS Lambda Power Tuning.
- Timeout is up to 15 minutes. Set it just above the realistic maximum; the default 3 seconds is too short for many real tasks. Long jobs belong in Step Functions, ECS or Batch.
- Ephemeral storage in
/tmpis configurable up to 10 GB.
Execution environments and cold starts
The first request to a new execution environment runs your initialization code (imports, SDK clients, configuration) before the handler: a cold start. Later requests reuse the warm environment. Keep initialization lean, create SDK clients outside the handler so they are reused, and for latency-critical APIs consider provisioned concurrency or SnapStart for Java. We go deeper in Lambda Cold Starts, VPC and Concurrency.
Concurrency
Each environment handles one request at a time, so concurrency equals the number of environments running at once. Accounts have a Regional concurrency quota (1,000 by default, raisable). Use reserved concurrency to cap a function (protecting a database behind it) or guarantee it capacity. When concurrency is exhausted, synchronous calls are throttled with a 429 error and asynchronous events are retried.
Reliability patterns
- Make handlers idempotent. Async and stream triggers can deliver the same event more than once. Use an idempotency key and conditional writes.
- Configure failure destinations or DLQs for async invocations, so failed events are kept rather than lost.
- For SQS triggers, set the queue's visibility timeout to at least six times the function timeout, use a redrive policy to a DLQ, and enable partial batch responses so one bad message does not fail a whole batch.
- Use versions and aliases to deploy safely, shifting traffic gradually with CodeDeploy and rolling back on alarms.
Pricing
You pay per request and per GB-second of duration (memory × time), billed in 1 ms increments, with a monthly free tier. Arm64 (Graviton) functions cost less per GB-second. The cost traps are usually around Lambda, not inside it: NAT gateway data for VPC functions, CloudWatch Logs ingestion from chatty logging, and retries multiplying work.
When not to use Lambda
Steady high-throughput services, jobs longer than 15 minutes, workloads needing special hardware or persistent connections, and latency-critical paths that cannot tolerate occasional cold starts are often better on ECS, EC2 or App Runner.
Practice it
Build an API in Serverless CRUD API: API Gateway, Lambda and DynamoDB, tune it in Lambda Tuning: Memory, Timeout, Reserved Concurrency and SQS DLQ, and release safely with Lambda Versions and Aliases. Then fix Orders Lambda Keeps Timing Out.
FAQ
Is Lambda really "serverless"?
There are servers, but AWS manages them, including patching, scaling and availability across AZs.
Can Lambda connect to a database in my VPC?
Yes. Attach the function to private subnets and a security group. Use RDS Proxy for relational databases to avoid exhausting connections.
How do I see logs?
Everything written to stdout or stderr goes to CloudWatch Logs, in a log group named /aws/lambda/<function-name>.