AWS Lambda Reference
Quotas, constraints, and gotchas that are easy to get wrong. Assumes you already know Lambda basics (packaging, layer paths, VPC-has-no-public-IP, Graviton ≈ 34% better price-performance, Powertools APIs) — this file focuses on the values and edge cases that trip up implementations.
Contents
- Cold Start Optimization
- Memory and Timeout Tuning
- VPC Connectivity
- Runtime Lifecycle
- Function URLs
- Powertools and Packaging
Cold Start Optimization
SnapStart
Snapshots the initialized execution environment (Firecracker microVM memory + disk) and restores from cache instead of cold-booting.
Supported runtimes: Java 11+, Python 3.12+, .NET 8+ — across both ZIP and container image deployment formats (including AWS Lambda base images and custom base images).
Constraints:
- Mutually exclusive with Provisioned Concurrency (cannot set both on one function)
- Mutually exclusive with Amazon EFS
- Ephemeral storage must be ≤ 512 MB
- Only works on published versions (not
$LATEST) - Java: no additional SnapStart charge. Python/.NET: caching charge (by memory, min 3 hours) + per-restore charge
Container images: For functions built on AWS Lambda base images or custom base images, see Implementing SnapStart hooks for container images and validate your function code against the SnapStart uniqueness requirements.
Restoration gotchas (snapshot is reused across restores):
- Generate unique IDs/secrets in the handler, not during init
- Re-establish network connections in the handler (connections are stale after restore)
- Refresh cached timestamps/credentials in the handler
# CDK (Python)
fn = lambda_.Function(self, "MyFunction",
runtime=lambda_.Runtime.PYTHON_3_13,
handler="index.handler",
code=lambda_.Code.from_asset("lambda"),
snap_start=lambda_.SnapStartConf.ON_PUBLISHED_VERSIONS,
)
version = fn.current_versionProvisioned Concurrency
Pre-initializes execution environments that stay warm permanently.
- A single instance handles one concurrent request at a time; throughput per instance = 1 / function duration
- Account-level RPS quota: 10 × total concurrency (applies across all invocations, not per instance)
- Supports auto-scaling via Application Auto Scaling (target ~70% utilization)
- Lambda can scale beyond provisioned count using on-demand instances
- Paid even when idle — disable in dev/staging
Strategy Selection
| Scenario | Strategy |
|---|---|
| Java/Python/.NET with heavy init | SnapStart |
| Strict <50ms cold start, or need EFS / >512MB ephemeral | Provisioned Concurrency |
| Tolerant of occasional cold starts | On-demand + minimize package |
| Steady, predictable traffic | Managed Instances (see compute-decision-edge-cases.md) |
| General price-performance (not a cold-start fix) | arm64 (Graviton) |
Memory and Timeout Tuning
Memory → CPU
| Parameter | Value |
|---|---|
| Range | 128 MB – 10,240 MB (1 MB increments), default 128 MB |
| 1 vCPU at | 1,769 MB |
| ~5.8 vCPUs at | 10,240 MB |
CPU scales linearly with memory — doubling memory doubles CPU. Over-provisioning memory often lowers cost (faster execution = less billed duration). Start at 256–512 MB; tune with AWS Lambda Power Tuning against Max Memory Used in REPORT lines.
Ephemeral storage (/tmp)
- 512 MB (default/min) – 10,240 MB; extra cost above 512 MB
- Persists across warm invocations (transient cache); NOT cleared after invoke failures
- SnapStart requires ≤ 512 MB
Timeout
- Range 1s – 900s (15 min); default is 3s — always set it explicitly
Critical integration limits:
- API Gateway REST API: 29s default — adjustable higher for Regional/private APIs; edge-optimized remains 29s max
- API Gateway HTTP API: 30s hard limit (cannot be raised)
- SQS visibility timeout should be ≥ 6× function timeout
Other limits worth knowing
| Resource | Limit |
|---|---|
| Sync invocation payload (request/response) | 6 MB each |
| Async invocation payload | 1 MB |
| Streamed response | 200 MB (2 MBps after first 6 MB) |
| Environment variables (total) | 4 KB |
| Concurrent executions (default) | 1,000 per region (soft) |
| Scaling rate | 1,000 new environments / 10s, per function |
VPC Connectivity
Lambda uses Hyperplane ENIs — shared across functions that use the same subnet + security group combination (NOT per-function). Each ENI supports ~65,000 connections.
- First-time ENI creation can take several minutes (function stays
Pending) - ENIs reclaimed after 14 days of inactivity (function goes
Inactive); removing VPC config takes up to 20 minutes
Reuse subnet + SG combos to share ENIs. Prefer VPC endpoints (gateway: S3, DynamoDB; interface: STS, Secrets Manager, SQS, …) over NAT Gateway for AWS-service access — lower latency, traffic stays on the AWS backbone. Don't attach to a VPC unless you need private resources (RDS, ElastiCache). VPC-attached functions need AWSLambdaVPCAccessExecutionRole.
Runtime Lifecycle
INIT ──▶ INVOKE (repeat) ──▶ SHUTDOWN [+ RESTORE phase for SnapStart]Init phase (extension init → runtime init → function init):
- On-demand init timeout: 10s. If exceeded, Lambda retries at first invocation using the function's configured timeout.
- Provisioned/SnapStart init timeout: up to 15 minutes.
Shutdown phase: 0 ms (no extensions), 500 ms (internal only), 2,000 ms (external extensions); SIGKILL if not done in time.
Restore phase (SnapStart): 10s timeout for restore + after-restore hooks.
Warm-start reuse
Objects initialized outside the handler persist across invocations (SDK clients, DB connections, /tmp). Gotchas:
- Execution environments are recycled periodically for maintenance even under continuous load — never assume an environment (or its warmed state) lives indefinitely.
- Global variables persist — stale DB connections, expired credentials, and leaked state across invocations cause subtle production bugs. Refresh connections/credentials in the handler.
Function URLs
A Function URL is a dedicated HTTPS endpoint on a single function — no API Gateway. Use for internal service-to-service (IAM auth), Lambdalith + CloudFront, response streaming, or webhook receivers. There's no built-in rate limiting, WAF, or request validation (front with CloudFront/API Gateway if you need those). Choose API Gateway instead for public APIs needing rate limiting, JWT/Cognito auth, multi-function routing, request validation, or WAF without CloudFront. For a Node.js app that already speaks HTTP (Express, Fastify, Hono), Lambda Web Functions serves it without an adapter or API Gateway — route to the aws-lambda-web-functions skill.
Invoking a Function URL always requires lambda:InvokeFunctionUrl and lambda:InvokeFunction — granting only InvokeFunctionUrl returns HTTP 403 even with AuthType=NONE. The two AuthType options differ in how those permissions are supplied:
AuthType=AWS_IAM (non-public — prefer for production)
Only callers with valid AWS credentials that sign requests with SigV4 can invoke; unauthenticated requests get 403.
- Same-account caller: grant the two actions in the caller's identity-based policy or the function's resource-based policy — a resource-based policy is optional if the caller's identity policy already allows them (this is why an admin/broad identity policy invokes with no resource policy on the function).
- Cross-account caller: requires both an identity-based policy on the caller and a resource-based policy on the function.
- For CloudFront in front, use Origin Access Control to sign requests rather than
NONE.
AuthType=NONE (public)
Lambda does no auth — the resource-based policy alone gates access, so it must grant public access. Only use when the endpoint must be reachable by unauthenticated clients (e.g. a browser hitting the URL directly) with no CloudFront/edge auth in front; it exposes the function to anyone with the URL, so pair it with in-code auth, throttling, and monitoring. The console and SAM add both required statements automatically; with the CLI/API add each yourself (two separate add-permission calls):
# Statement 1: allow invoking via the Function URL (public)
aws lambda add-permission --function-name my-function \
--statement-id FunctionURLAllowPublicAccess \
--action lambda:InvokeFunctionUrl --principal '*' \
--function-url-auth-type NONE
# Statement 2: REQUIRED — allow the underlying invoke, scoped to URL calls
aws lambda add-permission --function-name my-function \
--statement-id FunctionURLInvokeAllowPublicAccess \
--action lambda:InvokeFunction --principal '*' \
--invoked-via-function-urlThe lambda:InvokedViaFunctionUrl condition on statement 2 (set by --invoked-via-function-url) restricts that grant to Function URL calls, so it does not open direct Invoke access. See Lambda function URL auth.
Powertools and Packaging
Use Powertools for AWS Lambda (Python, TypeScript, Java, .NET) for structured logging, X-Ray tracing, EMF metrics, idempotency, batch processing, event handling, and parameter caching. The APIs are well-documented at docs.powertools.aws.dev; for a ready-to-use Python handler with Logger + Tracer + Metrics + Idempotency wired, start from assets/powertools-handler.py.
Powertools adds cold-start overhead — use selective imports when cold start is critical.
Useful Powertools env vars: POWERTOOLS_SERVICE_NAME, POWERTOOLS_METRICS_NAMESPACE, POWERTOOLS_LOG_LEVEL, POWERTOOLS_TRACE_DISABLED (tests), POWERTOOLS_DEV (pretty-print).
Packaging quick facts: 50 MB zipped / 250 MB unzipped (incl. layers) → switch to container image (10 GB) past that. Max 5 layers/function; layers don't work with container images. Use uv pip install (10–100× faster than pip) and --platform manylinux2014_{x86_64,aarch64} --only-binary=:all: for cross-platform builds, or let sam build handle it. See troubleshooting.md for size/import errors.