How Lambda Scales
Lambda's scaling model is simple: one concurrent request equals one execution environment. If 1,000 requests arrive simultaneously, Lambda attempts to run 1,000 MicroVMs in parallel. By default, your AWS account has a regional concurrency limit of 1,000 (soft limit, can be raised). This limit is shared across all Lambda functions in the region.
This default behavior is powerful but can cause problems. An unexpected traffic spike on one function could consume the entire regional concurrency pool, throttling every other Lambda function in your account. This is why concurrency controls exist.
Reserved Concurrency — The Hard Ceiling
Reserved Concurrency sets a maximum number of concurrent instances for a specific function. It works in two directions simultaneously:
- Protects downstream resources: If your database handles at most 50 connections, setting Reserved Concurrency to 50 ensures Lambda never opens more than 50 simultaneous connections.
- Protects other functions: The reserved capacity is subtracted from the regional pool, guaranteeing it's available for this function and not consumed by others.
Setting it is a single configuration call against the function — you specify the function name and the concurrent-execution ceiling, and Lambda enforces it immediately.
The throttling side effect: If 51 requests arrive simultaneously, the 51st is throttled — Lambda returns a 429 TooManyRequestsException. For synchronous invocations (API Gateway), this surfaces as an HTTP 429 to the caller. For asynchronous invocations (SQS, EventBridge), Lambda retries automatically. Setting Reserved Concurrency to 0 effectively disables a function entirely — useful for emergency shutoffs.
Provisioned Concurrency — The Pre-warmed Fleet
Provisioned Concurrency tells Lambda to keep a specific number of execution environments initialized and ready at all times, regardless of traffic. These environments have already completed the Init Phase — they are permanently warm.
Configuring it is a single call targeting a specific published version or alias (never $LATEST) with the desired count of pre-warmed environments — in this example, keeping 100 environments permanently initialized.
When a request arrives, it is immediately routed to one of these pre-warmed environments — zero cold start. If traffic exceeds 100 concurrent requests, the 101st request triggers a standard cold start (or is throttled if Reserved Concurrency is also set).
Cost reality: Provisioned Concurrency is billed by the GB-second of provisioned capacity, regardless of whether those environments are handling requests. 100 provisioned environments running 24/7 for a month costs roughly $140–$400 depending on memory configuration. Use it only for latency-sensitive, user-facing functions where cold starts are genuinely unacceptable.
Choosing Between Them
| Scenario | Use |
|---|---|
| Protect a database with connection limits | Reserved Concurrency |
| Prevent one function from starving others | Reserved Concurrency |
| Eliminate cold starts for a user-facing API | Provisioned Concurrency |
| Emergency disable a runaway function | Reserved Concurrency = 0 |
| Guarantee capacity during a known traffic event | Provisioned Concurrency |
A common interview trap: "Can you use Provisioned Concurrency to protect your database from connection exhaustion?" The answer is no — Provisioned Concurrency sets a floor (minimum warm instances), not a ceiling. Traffic can still scale beyond the provisioned count. To protect downstream resources, you need Reserved Concurrency (the ceiling). You can use both simultaneously: Provisioned Concurrency for warm starts up to N, and Reserved Concurrency to cap the total at M.