Provisioned Concurrency & Cold-Start Management
Provisioned concurrency keeps a set number of execution environments initialized and ready, so invokes on that path do not pay a cold start.
Busque em todas as páginas da documentação
Provisioned concurrency keeps a set number of execution environments initialized and ready, so invokes on that path do not pay a cold start.
For a latency-sensitive API behind Lambda, the tail latency from cold starts is often the problem. Provisioned concurrency removes it for a fixed slice of capacity by building the environments ahead of time. This page shows how to configure it on a version or alias, confirm it is ready, and how it differs from reserved concurrency - all through the SDK.
Publish a version (or use an alias), then set provisioned concurrency on that qualifier.
$LATESTis not allowed.
# --- Python (boto3) ---
import boto3
lam = boto3.client("lambda")
lam.put_provisioned_concurrency_config(
FunctionName="checkout",
Qualifier="prod", # an alias or version, not $LATEST
ProvisionedConcurrentExecutions=20,
)// --- TypeScript (AWS SDK v3) ---
import { LambdaClient, PutProvisionedConcurrencyConfigCommand } from "@aws-sdk/client-lambda";
const lam = new LambdaClient({});
await lam.send(new PutProvisionedConcurrencyConfigCommand({
FunctionName: "checkout",
Qualifier: "prod", // an alias or version, not $LATEST
ProvisionedConcurrentExecutions: 20,
}));When to reach for this:
A realistic rollout: set provisioned concurrency on the prod alias, wait until it is READY, and read back the allocation.
# --- Python (boto3) ---
import boto3, time
lam = boto3.client("lambda")
lam.put_provisioned_concurrency_config(
FunctionName="checkout",
Qualifier="prod",
ProvisionedConcurrentExecutions=20,
)
# Allocation is asynchronous - poll until READY.
while True:
cfg = lam.get_provisioned_concurrency_config(FunctionName="checkout", Qualifier="prod")
status = cfg["Status"]
if status in ("READY", "FAILED"):
break
time.sleep(5)
print(status, cfg.get("AllocatedProvisionedConcurrentExecutions"))
if status == "FAILED":
print("reason:", cfg.get("StatusReason"))// --- TypeScript (AWS SDK v3) ---
import {
LambdaClient,
PutProvisionedConcurrencyConfigCommand,
GetProvisionedConcurrencyConfigCommand,
} from "@aws-sdk/client-lambda";
const lam = new LambdaClient({});
await lam.send(new PutProvisionedConcurrencyConfigCommand({
FunctionName: "checkout",
Qualifier: "prod",
ProvisionedConcurrentExecutions: 20,
}));
// Allocation is asynchronous - poll until READY.
let cfg;
do {
cfg = await lam.send(new GetProvisionedConcurrencyConfigCommand({ FunctionName: "checkout", Qualifier: "prod" }));
if (cfg.Status === "READY" || cfg.Status === "FAILED") break;
await new Promise((r) => setTimeout(r, 5000));
} while (true);
console.log(cfg.Status, cfg.AllocatedProvisionedConcurrentExecutions);
if (cfg.Status === "FAILED") console.log("reason:", cfg.StatusReason);What this demonstrates:
Status moves IN_PROGRESS to READY (or FAILED) as environments spin up.AllocatedProvisionedConcurrentExecutions shows how many are actually warm; Available shows how many are idle right now.prod alias) so the config follows your traffic across deploys.FAILED, StatusReason explains why (often an account concurrency limit).A cold start is the time to create an execution environment and run initialization before the handler. Provisioned concurrency does that work in advance and keeps the environments parked. When an invoke arrives and a provisioned environment is free, the handler runs immediately - no download, no runtime start, no init. Only invokes beyond the provisioned count fall back to on-demand cold starts.
Provisioned concurrency is billed for the time it is allocated, whether or not it is used. Set it to your steady or expected-peak concurrency, and let on-demand absorb spikes above it. To follow a daily traffic curve without over-paying at night, use Application Auto Scaling (the application-autoscaling API) to schedule or target-track the provisioned count on the alias.
PutProvisionedConcurrencyConfig rejects $LATEST. Warm capacity must attach to an immutable target: a published version, or an alias pointing at one. During a version cutover, warm the new version (or point the alias at it and warm the alias) before shifting traffic, so the new code is ready when it takes load.
They solve different problems and can be combined:
| Reserved concurrency | Provisioned concurrency | |
|---|---|---|
| Purpose | Cap/guarantee how many environments a function may use | Pre-warm a fixed number so they skip cold start |
| API | PutFunctionConcurrency | PutProvisionedConcurrencyConfig |
| Target | The function | A version or alias |
| Cost | No direct charge | Billed for allocated capacity |
| Effect on cold starts | None | Eliminates them up to the provisioned count |
Before paying for provisioned concurrency, cut the cold start itself: shrink the deployment package, move heavy work out of the init path, raise memory (which raises CPU and speeds init), and avoid unnecessary VPC attachment. Provisioned concurrency is the tool when those are not enough for a latency-critical path.
$LATEST. The call rejects it. Fix: publish a version or use an alias as the Qualifier.GetProvisionedConcurrencyConfig until Status is READY.DeleteProvisionedConcurrencyConfig.StatusReason on FAILED and request a limit increase.PutFunctionConcurrency to cap, PutProvisionedConcurrencyConfig to pre-warm.| Alternative | Use When | Don't Use When |
|---|---|---|
| Provisioned concurrency | A latency-critical path cannot tolerate cold starts | Cold starts are rare or latency-tolerant |
| Optimize package/init | You want cheaper, always-on cold-start reduction | Init is already minimal and latency still misses target |
| Application Auto Scaling on provisioned | Traffic follows a predictable curve | Traffic is flat, so a static count is simpler |
| Reserved concurrency | You need to cap or guarantee capacity, not warm it | The goal is latency, not a concurrency ceiling |
| SnapStart (supported runtimes) | You want cold-start reduction without always-on cost | Your runtime/config does not support it |
It pre-initializes a fixed number of execution environments and keeps them ready. Invokes that land on a warm environment skip the cold start entirely; invokes beyond the provisioned count still cold-start on demand.
Warm capacity must attach to an immutable target. PutProvisionedConcurrencyConfig only accepts a published version or an alias, so the code being kept warm cannot change underneath it.
Poll GetProvisionedConcurrencyConfig until Status is READY. AllocatedProvisionedConcurrentExecutions tells you how many are warm; a FAILED status includes a StatusReason.
No. Reserved concurrency (PutFunctionConcurrency) caps or guarantees how many environments a function may use. Provisioned concurrency pre-warms a number of them. You can use both together.
Yes. You are billed for the allocated provisioned capacity for as long as it is configured, used or not. Scale it down off-peak or delete it when unneeded.
Use Application Auto Scaling (application-autoscaling) to schedule or target-track the provisioned count on the alias, raising it during peak hours and lowering it overnight.
It runs as normal on-demand concurrency, which means those invokes can cold-start. Size the provisioned count to the load you need consistently fast.
Usually yes. Trimming the package, reducing init work, and raising memory are cheaper and help everywhere. Reach for provisioned concurrency when a latency-critical path still misses its target.
Stack versions: This page was written for boto3 1.43.x (Python 3.10+) and the AWS SDK for JavaScript v3 (Node.js 18+).
Revisado por Chris St. John·Última atualização: 23 de jul. de 2026