AWS Lambda Best Practices
Opinionated, language-agnostic conventions for designing and operating Lambda functions at scale. For SDK/API usage, infrastructure-as-code definitions, or language-specific handler patterns, consult the relevant AWS SDK or Terraform documentation instead.
Is Lambda the Right Choice?
Lambda excels at event-driven, short-lived, stateless workloads. Evaluate fit before committing.
| Requirement | Lambda fit | Better alternative |
|---|---|---|
| Event-driven, bursty traffic | Excellent | -- |
| Execution < 15 minutes | Good | ECS/Fargate for longer tasks |
| Stateless request/response | Excellent | -- |
| Persistent connections (WebSockets) | Poor | API Gateway WebSocket + ECS |
| Predictable, steady-state high throughput | Evaluate cost | ECS/Fargate or EC2 |
| GPU or specialized hardware | Not supported | EC2 or SageMaker |
| Large deployment artifact (> 10 GB) | Container image limit | ECS/Fargate |
| Sub-millisecond latency | Not achievable -- invocation overhead is milliseconds even on warm starts | EC2 or containers |
Function Design
One function per responsibility. Scope by event source or business operation. Keep the handler thin: validate input, delegate to business logic (pure functions), return a structured response. Initialize SDK clients and connections at module level -- Lambda reuses the execution environment across invocations.
Don't: build a Lambda monolith (all routes in one function), inline business logic in the handler, or create connections inside the handler.
Idempotency is mandatory. Lambda guarantees at-least-once invocation -- your function will receive duplicates. Use an idempotency key (request ID, message ID) with DynamoDB or Powertools to prevent reprocessing.
Don't: write orchestration logic in Lambda. If your function has more if/else/retry than business logic, move the workflow to Step Functions. Never have Lambda synchronously invoke another Lambda -- use SQS or Step Functions to decouple.
Don't: write to the same resource that triggered the function -- this causes recursive invocation loops with exponential cost. If detected, set reserved concurrency to 0 immediately.
See references/function-design.md for execution environment reuse details, cold start factors, idempotency implementation, connection management, and environment variables. See references/anti-patterns.md for why each anti-pattern feels right but isn't, impact analysis, and migration strategies.
Function Configuration
Memory and CPU -- they are linked
Lambda allocates CPU proportional to memory. At 1,769 MB, a function gets one full vCPU.
| Memory | CPU | Best for |
|---|---|---|
| 128-512 MB | Fractional vCPU | Simple transforms, routing |
| 512-1,769 MB | Up to 1 vCPU | API handlers, moderate processing |
| 1,769-3,008 MB | 1-2 vCPU | Data processing, image manipulation |
| 3,008-10,240 MB | 2-6 vCPU | ML inference, heavy computation |
Use AWS Lambda Power Tuning to find the optimal price/performance balance.
Architecture -- default to arm64
arm64 (Graviton) costs 20% less per GB-second than x86_64 with equal or better performance. Use it unless a native dependency, layer, or container base image requires x86_64.
Timeout -- set deliberately, not defensively
Set to p99 duration + 20-50% buffer. For SQS triggers, set SQS Visibility Timeout >= 6x function timeout. API Gateway's integration timeout is 29 seconds by default (raisable above that only for Regional/private REST APIs via quota increase).
Key quotas
| Resource | Limit | Notes |
|---|---|---|
| Max execution time | 15 minutes | Hard limit |
| Payload (sync) | 6 MB request / 6 MB response | 200 MB for streamed responses |
| Payload (async) | 1 MB | -- |
| Deployment package (.zip) | 50 MB zipped / 250 MB unzipped | Use S3 for larger uploads |
| Container image | 10 GB | -- |
/tmp storage |
512 MB - 10,240 MB | Configurable |
| Environment variables | 4 KB total | Aggregate across all variables |
| Concurrent executions | 1,000 default | Soft limit, increase via Service Quotas |
| Layers | 5 per function | -- |
See references/function-configuration.md for memory/CPU tuning strategies, architecture selection, IAM policy guidance, SQS integration, and quota management.
Function Scalability
Concurrency model
Concurrency = (requests per second) x (average duration in seconds)
100 RPS with 200ms average duration = 20 concurrent executions.
Choosing a concurrency control
| Scenario | Control | How to size |
|---|---|---|
| Most functions, no special needs | Unreserved (default) | Shares account pool (1,000 default) |
| Critical function that must always have capacity | Reserved concurrency | Peak concurrent executions x 1.3 |
| Protect downstream from overload (DB, API) | Reserved concurrency | Match downstream's safe throughput |
| User-facing API with latency SLA | Provisioned concurrency | Eliminates cold starts; use auto-scaling |
| Emergency stop for runaway function | Reserved concurrency = 0 | Halts all invocations immediately |
Lambda scales automatically -- your dependencies may not. Use RDS Proxy for relational databases, reserved concurrency to cap scaling to third-party rate limits, and on-demand mode for DynamoDB under Lambda workloads.
Don't: let Lambda overwhelm your database. A traffic spike -> 1,000 concurrent functions -> 1,000 simultaneous DB connections -> connection exhaustion -> all functions timeout -> cascade failure. This is the most common Lambda production incident.
See references/function-scalability.md for scaling rate, provisioned concurrency scheduling, throttle tolerance patterns, upstream/downstream protection, and cascade failure prevention.
Metrics and Alarms
Prefer Embedded Metric Format (EMF) over PutMetricData API calls for custom metrics -- zero latency overhead. Use Powertools for AWS Lambda to handle EMF formatting. Use PutMetricData only when you need high-resolution (1-second) metrics or immediate availability.
Key metrics to alarm on
| Metric | Alarm condition | What it catches |
|---|---|---|
Errors |
> 0 for N minutes | Function failures |
Throttles |
> 0 | Hitting concurrency limits |
Duration |
p99 > threshold | Latency degradation |
ConcurrentExecutions |
> 80% of reserved | Approaching ceiling |
IteratorAge (streams) |
> 30,000 ms | Falling behind on stream processing |
DeadLetterErrors |
> 0 | DLQ delivery failures |
Use structured JSON logging, correlation IDs across services, X-Ray tracing, and Cost Anomaly Detection.
See references/metrics-and-alarms.md for EMF details, structured logging guidance, alarm configuration, and cost anomaly detection setup.
Working with Streams
Batch tuning is the critical lever -- larger batches amortize overhead, batching windows buffer small batches. Always enable ReportBatchItemFailures in production to retry only failed records instead of the entire batch. Every stream-processing function must be idempotent -- at-least-once delivery is guaranteed.
| Stream type | Scaling lever | Concurrency model |
|---|---|---|
| Kinesis | Add shards | 1 invocation per shard (default); up to 10 with parallelization factor |
| DynamoDB Streams | Add partitions (indirect) | 1 invocation per shard |
| SQS | Automatic | Lambda scales pollers up to concurrency limit |
See references/stream-events.md for batch tuning parameters, partial batch response implementation, Kinesis shard management, IteratorAge monitoring, and SQS FIFO considerations.
Security
IAM -- least privilege, always. One narrowly scoped execution role per function. No wildcards in production. Use resource-based policies to control who can invoke your function.
| Practice | Why |
|---|---|
| Code signing | Verify deployment artifact integrity |
| VPC placement | Required for private resources; minor cold start impact (Hyperplane ENIs) |
| Security Hub controls | Automated CSPM checks against Lambda configurations |
| GuardDuty Lambda Protection | Monitors for threats (crypto mining, C2 communication) |
| Secrets Manager / Parameter Store | Never hardcode secrets |
See references/security.md for VPC configuration trade-offs, code signing setup, secrets management patterns, data protection, and governance strategies.
Common Mistakes
| Mistake | Fix |
|---|---|
| Initializing SDK clients inside the handler | Move to module/global scope for execution environment reuse |
| Setting timeout to 15 minutes "just in case" | Set to p99 duration + reasonable buffer; load test |
| Ignoring cold starts for user-facing APIs | Use provisioned concurrency, SnapStart (Java/Python/.NET), or optimize package size |
| Not designing for idempotency | Use idempotency keys with DynamoDB or Powertools |
| Recursive invocations (function triggers itself) | Set reserved concurrency to 0 immediately; fix the trigger/output separation |
| Hardcoding resource names | Use environment variables for bucket names, table names, endpoints |
| Wildcard IAM permissions | Grant specific actions on specific resources |
| Not monitoring IteratorAge on streams | Alarm at 30s; add shards or increase parallelization |
| Retrying the full batch on partial failure | Enable ReportBatchItemFailures |
| Over-provisioning memory without testing | Use Lambda Power Tuning to find optimal setting |
Reference Files
references/anti-patterns.md-- Lambda monolith, Lambda as orchestrator, synchronous chains, recursive loops, synchronous waiting -- why each feels right, impact analysis, migration strategiesreferences/function-design.md-- Execution environment reuse, cold start factors, idempotency implementation, connection management, RDS Proxy, environment variablesreferences/function-configuration.md-- Memory/CPU tuning strategies, arm64/Graviton selection, timeout alignment, quotas, IAM policies, SQS integration, cleanupreferences/function-scalability.md-- Concurrency estimation, reserved vs provisioned concurrency, scaling rate, upstream/downstream protection, cascade failure preventionreferences/metrics-and-alarms.md-- CloudWatch metrics, EMF implementation, structured logging, alarm configuration, Cost Anomaly Detection, X-Ray tracingreferences/stream-events.md-- Batch tuning, partial batch response, Kinesis/DynamoDB Streams/SQS scaling, IteratorAge monitoring, SQS FIFO high-throughput modereferences/security.md-- IAM least privilege, code signing, VPC trade-offs, secrets management, data protection, Security Hub, GuardDuty, governance