Skip to main content
INS // Insights

Lambda Provisioned Concurrency: When It's Waste, Not a Fix

Updated September 2026 · 4 min read
Lambda Provisioned Concurrency: When It's Waste, Not a Fix

Provisioned concurrency keeps a set number of Lambda execution environments warm and ready, eliminating cold-start latency for latency-sensitive workloads. It's billed by the hour for the configured concurrency level, regardless of whether those environments are actually invoked — which means it's easy to configure once for a real latency problem and then keep paying for capacity long after traffic patterns change.

What Provisioned Concurrency Actually Costs

Provisioned concurrency bills a separate rate on top of standard Lambda invocation and duration charges, applied continuously for every configured concurrent execution environment, 24/7, whether invoked or not. For a function configured with 20 provisioned concurrent executions running around the clock, that's 20 environments billed continuously — a real, ongoing cost independent of actual traffic.

The Cold-Start Problem It's Meant to Solve

Cold starts happen when Lambda needs to initialize a new execution environment — downloading code, starting the runtime, running initialization code — before it can process an invocation. For latency-sensitive synchronous workloads (an API Gateway-backed endpoint with a tight SLA), a cold start of a few hundred milliseconds to a few seconds can be a real user-facing problem. Provisioned concurrency solves this by keeping environments pre-initialized.

When It's the Right Tool

  • Synchronous, latency-sensitive endpoints with strict SLA requirements where even occasional cold starts violate the SLA
  • Predictable traffic patterns where you can size provisioned concurrency to match actual concurrent load, rather than guessing
  • Functions with heavy initialization code (large dependencies, database connection setup) where cold starts are particularly slow

When It's Quietly Wasting Money

import boto3
from datetime import datetime, timedelta

cloudwatch = boto3.client("cloudwatch")
lambda_client = boto3.client("lambda")

def audit_provisioned_concurrency_utilization(function_name):
    """Compares configured provisioned concurrency against actual
    concurrent execution metrics to find over-provisioned functions."""
    config = lambda_client.get_provisioned_concurrency_config(
        FunctionName=function_name, Qualifier="live"
    )
    configured = config["RequestedProvisionedConcurrentExecutions"]

    metrics = cloudwatch.get_metric_statistics(
        Namespace="AWS/Lambda",
        MetricName="ProvisionedConcurrentExecutions",
        Dimensions=[{"Name": "FunctionName", "Value": function_name}],
        StartTime=datetime.utcnow() - timedelta(days=14),
        EndTime=datetime.utcnow(),
        Period=3600,
        Statistics=["Average", "Maximum"],
    )
    avg_used = sum(m["Average"] for m in metrics["Datapoints"]) / max(len(metrics["Datapoints"]), 1)
    return {
        "function": function_name,
        "configured": configured,
        "avg_actual_usage": round(avg_used, 2),
        "utilization_pct": round((avg_used / configured) * 100, 1) if configured else 0,
    }

Functions consistently showing utilization well under 50% of their configured provisioned concurrency are a strong signal the setting was configured for a traffic spike that either never fully materialized or has since declined, and the ongoing cost hasn't been revisited.

The Auto-Scaling Middle Ground

Application Auto Scaling can adjust provisioned concurrency on a schedule or based on utilization metrics, which handles predictable daily traffic patterns (busy business hours, quiet overnight) without requiring manual reconfiguration or accepting a flat rate sized for peak load around the clock.

A Cheaper Alternative Worth Testing First

Lambda SnapSnap (available for certain runtimes) can reduce cold-start latency without the continuous cost of provisioned concurrency, by caching a snapshot of an initialized execution environment. For functions where the latency requirement is real but not extremely strict, this is worth testing before committing to provisioned concurrency's ongoing cost.

Frequently Asked Questions

How often should we review provisioned concurrency settings?

Monthly is reasonable for functions with meaningful spend, especially after any change in traffic patterns, feature launch, or deprecation of a dependent service that used to drive load.

Does removing provisioned concurrency bring back the original cold-start problem immediately?

Yes — removing it reverts to standard on-demand execution environment initialization, so this should only be done after confirming the latency requirement that originally justified it either no longer applies or can tolerate standard cold starts.

Can auto-scaling schedules fully replace manual provisioned concurrency tuning?

For predictable traffic patterns, yes, largely. For genuinely unpredictable or bursty traffic, scheduled scaling won't react fast enough, and a different approach — like combining a smaller baseline with SnapStart — may fit better.

Is there a way to test the latency impact before committing to provisioned concurrency?

Yes — load testing the function under realistic concurrent traffic with and without provisioned concurrency enabled gives a direct before/after latency comparison to justify the ongoing cost.

See what an AWS cost audit finds in your Lambda spend → rutagon.com/contact or call 907-841-8407.