A Lambda cold start happens when the service creates a new execution environment. Lambda must prepare the environment, start the runtime and extensions, and run initialization code outside the handler before it can process the request. Lambda bills for this initialization work; current function-duration charges are rounded up to the nearest millisecond. Later requests may reuse an environment, but Lambda can retire it or create more environments as traffic changes. A previous invocation or a scheduled ping does not guarantee that the next request will be warm. See current AWS Lambda pricing.
First separate initialization latency from invocation work. The CloudWatch Duration metric measures invocation time after the Init phase; the Init Duration value appears in execution logs when initialization runs. It is a log field, not a standard Lambda CloudWatch metric. Successful on-demand initialization is reported with the invocation's REPORT record; provisioned concurrency and SnapStart also emit INIT_REPORT records. With SnapStart, Init Duration describes initialization when Lambda prepares a version snapshot; a request that restores a new environment reports Restore Duration and Billed Restore Duration in its REPORT record. AWS defines SnapStart cold-start duration as Restore Duration plus Duration. Compare these signals with end-to-end latency and downstream call time before choosing a fix. For alarms on standard metrics such as errors, duration, and throttles, see our guide to setting up CloudWatch alarms for Lambda. AWS explains the execution environment lifecycle, Lambda log fields, and SnapStart monitoring fields.
What a cold start includes
Initialization can include code and dependency loading, runtime startup, extension startup, and setup work such as creating a client or opening a connection. A slow request is not automatically a cold start: the handler, a database, DNS, TLS, or another service can also dominate latency after initialization. Lambda's standard Duration metric excludes the Init phase, so use the log fields or platform events to inspect startup directly.
For an on-demand function, the first Init phase is limited to 10 seconds. If it does not finish, Lambda retries initialization during the first invocation using the function timeout. For provisioned concurrency and SnapStart, the initialization limit is the greater of 130 seconds or the configured function timeout, up to 900 seconds. These are platform limits, not performance targets; see AWS's current initialization and restore limits.
1. Use provisioned concurrency for latency targets
Provisioned concurrency (PC) allocates execution environments that Lambda initializes before requests arrive. It is the direct control for reducing initialization on a known amount of latency-sensitive traffic, such as an interactive API. It does not make the handler or its downstream calls faster.
How it works
Configure PC on a published function version or an alias that points to one; it cannot be configured on $LATEST. Route the event source or caller through that same version or alias. If the function has a reserved concurrency limit, the PC allocation cannot exceed it. Reserved concurrency by itself only reserves and caps concurrency; it does not initialize environments or prevent cold starts.
Choose the PC amount from observed peak concurrent requests and the latency you need to protect. If every provisioned environment is busy, additional invocations can spill over to standard on-demand concurrency and may incur a cold start. Check ProvisionedConcurrencyUtilization and ProvisionedConcurrencySpilloverInvocations in CloudWatch; use them to adjust the allocation or scale PC for known traffic patterns with Application Auto Scaling. See AWS's provisioned concurrency guide and concurrency metrics reference.
Cost and capacity
PC has a separate charge for the allocated capacity while it is enabled, even when that capacity is idle; current pricing rounds that allocation time up to five-minute increments. You also pay the applicable request and invocation-duration charges. Lambda can recycle provisioned environments and rerun initialization; that initialization is billable even if an environment handles no request. Function duration, including initialization and extension shutdown work, is rounded up to the nearest millisecond. Memory size, architecture, Region, and how long PC is allocated affect the bill, so compare the expected pattern with the current AWS Lambda pricing before setting a permanent allocation.
When it fits
Use PC when a measured cold-start tail threatens a user-facing latency objective and paying for ready capacity is justified. For predictable daily or launch peaks, schedule PC ahead of the expected rise and reduce it afterward. Keep headroom for bursts: traffic above the allocation uses standard concurrency, and PC does not guarantee that spillover requests will be initialized in advance.
Why EventBridge pings are not a readiness guarantee
An EventBridge schedule can invoke a function periodically, and Lambda may reuse the environment that handled that invocation. It does not reserve an environment, control how long Lambda retains it, or prepare enough environments for concurrent traffic. A burst can therefore create new environments even while scheduled calls continue.
Those calls also consume EventBridge and Lambda requests and execution time. Their cost may be small for some workloads, but it grows with the schedule and any concurrency used by a warmer. Measure the result rather than assuming it is negligible.
Treat scheduled warm-up as a best-effort experiment for noncritical traffic, never as an availability or latency guarantee. For a strict latency objective, provision the capacity that the workload needs and monitor spillover.
Warm-up plugins have the same limit
A plugin can automate scheduled invocations and target selection, but it cannot change Lambda's environment lifecycle. It still cannot guarantee reuse of the same environment or prepare for an unplanned concurrency spike.
Account for the warmer's own schedule, invocation time, and any requested concurrency. Disable schedules outside the periods where measured benefit justifies the cost.
If a warmer remains useful, keep it isolated from normal business logic and verify its effect with production-shaped traffic. Do not describe it as eliminating cold starts.
2. Use SnapStart when the runtime and function are eligible
Lambda SnapStart initializes a function version when you publish it, saves a snapshot of the initialized environment, and restores new environments from that snapshot. This can reduce the work on startup without keeping a fixed number of environments allocated. AWS currently documents SnapStart for managed Java 11 and later, Python 3.12 and later, and .NET 8 and later runtimes, including their corresponding Lambda base images for ZIP and container deployments. Custom container base images require SnapStart hooks and compatibility validation. Check the current SnapStart runtime, Region, and feature requirements for your deployment.
SnapStart applies only to published versions and aliases, not $LATEST, and it cannot be combined with provisioned concurrency. It also has feature limits, including no support for EFS, S3 Files, or ephemeral storage above 512 MB. For supported runtimes, account for snapshot caching per active function version (with a three-hour minimum) and a charge for each restore, as well as normal invocation costs. AWS currently lists no additional SnapStart charge for managed Java runtimes. Check current pricing for the function's runtime and Region.
A snapshot can preserve state that normally should be unique or fresh. Generate unique IDs, random seeds, tokens, timestamps, and other per-environment values after restore or in the handler. Validate initialized network connections and reconnect when needed. SnapStart runtime hooks can run code before checkpointing or after restore, but after-restore hooks add billed restore time and must complete within 10 seconds. Read AWS's guidance on handling uniqueness and runtime hooks before enabling it.
3. Reduce work in the initialization path
The function's static initialization runs when Lambda creates an environment. Imports, frameworks, large dependency trees, layers, and setup calls can all add work before the handler starts. Start by identifying what each function actually needs, then remove unused dependencies and initialization.
Load only what the function uses
Import only the libraries and AWS SDK clients the function needs. Where the SDK supports it, use a service-specific package rather than loading an entire SDK.
Move optional or rarely used dependencies behind the code path that needs them. This can shorten startup for common requests, although the first request that needs that feature then pays its initialization cost.
Initialize reusable clients outside the handler when that avoids rebuilding them on every invocation. Make network clients able to recover from expired connections and do not put per-request user state in globals.
A smaller artifact can help when it means less code and fewer dependencies to load, but a package-size target alone does not predict startup time. Measure before splitting one function into several: smaller functions can have less initialization, while extra calls and deployments can add latency and maintenance.
Keep the deployed artifact purposeful
Remove libraries, layers, locale data, and other assets the function does not use. Bundle only the modules needed at runtime and compare the change with the same cold-start workload. Avoid an arbitrary package-size threshold; the amount of code loaded and the work it performs matter more than a universal file-size target.
Respect the initialization limit
If ordinary on-demand initialization repeatedly approaches its 10-second limit, profile each import and setup call rather than moving everything into the handler. The handler's configured timeout applies when Lambda retries an incomplete initialization; PC and SnapStart have their longer, separate initialization limits. A longer limit is not a reason to keep avoidable work.
Extensions also initialize before the handler. Review the section on measuring extensions if startup logs point to an extension rather than application code.
4. Choose a runtime by benchmarking your workload
There is no universal cold-start ranking that makes one language fastest for every Lambda function. Startup depends on the runtime and version, package and layers, framework and import work, architecture, and what the code initializes. A compiled runtime can still have expensive initialization, while a dynamic-language function with a small dependency tree can start quickly.
Compare equivalent deployments
If runtime choice is still open, benchmark the same representative function, dependencies, memory setting, architecture, and deployment format on each viable runtime. Measure cold-start logs, end-to-end latency percentiles, handler duration, and cost. Include the application's normal downstream calls so the comparison reflects what users wait for.
Include migration and support cost
Changing languages or runtimes can improve startup for a particular application, but rewriting business logic and maintaining another stack can cost more than the saved milliseconds. Prefer a runtime that your team can support and keep on a currently supported Lambda runtime; check AWS's runtime support and deprecation list.
Use measurements, not a language table
Keep the current runtime when its measured startup meets the requirement. Change it only when representative tests show a meaningful end-to-end improvement after accounting for compatibility, deployment size, and operating cost.
5. Tune memory to give initialization more CPU
How memory changes compute
Lambda allocates more CPU as you increase a function's memory. That can speed up CPU-bound startup work such as loading or processing libraries, but it will not fix time spent waiting on a remote service. Use a small set of memory configurations and compare initialization duration and handler duration separately.
Compare total cost, not cost per millisecond
A higher memory setting raises the price per unit of duration. If it shortens execution enough, total cost may stay similar or fall; if it does not, the extra allocation adds cost without solving the delay. Test with representative cold and warm invocations and inspect memory use before choosing a setting. AWS documents the memory-to-CPU relationship in its Lambda performance best practices.
When to try it
Test memory tuning when the function uses substantial CPU during initialization or handler execution. For I/O-bound initialization, inspect connection setup and downstream latency instead of raising memory as a blanket fix.
6. Fix first-use connection work without blaming every VPC
Creating a database connection, resolving a name, negotiating TLS, or loading credentials can make the first request slower. Separate this application and dependency work from Lambda's environment setup. Reuse SDK clients or connections across invocations when they are safe to reuse, and validate or recreate connections because an environment can be frozen, resumed, or replaced.
Every Lambda function runs in a Lambda-managed VPC. Attaching a function to a VPC in your account gives it access to private resources and uses managed Hyperplane network interfaces. Lambda can share an interface among functions with the same subnet and security-group combination; creating the first interface for a new combination is a configuration operation that can take minutes. This is not a fresh customer VPC interface created for every invocation. Keep a VPC connection when the function needs private resources, and investigate measured connection setup or network errors before changing it. See AWS's current Lambda VPC and Hyperplane ENI guidance.
If only one code path needs a client or connection, initialize it for that path rather than making every cold start pay for unused setup. If most requests need it, initialize a reusable client early and check its health before reuse. Either choice should follow measured traffic and connection behavior.
7. Measure extensions before keeping them
What an extension changes
Extensions add monitoring, security, or other tools to the execution environment, but they do not pre-warm Lambda. Every extension must complete initialization before Lambda invokes the handler. Extensions also share the function's CPU, memory, and storage, so a slow extension can increase startup latency or compete with application work.
Account for extension work
AWS charges for the time an extension consumes in 1 ms duration increments, including its remaining work after the handler finishes. A partner may also charge for its product. Use PostRuntimeExtensionsDuration to investigate extension time after the function runs, and compare versions with and without an optional extension under the same workload.
Keep the tools that earn their cost
Keep an extension when its monitoring, security, or governance value justifies its startup, resource, and billing impact. Remove or reconfigure extensions that add work without serving a requirement. For lifecycle and performance details, see AWS's Lambda extensions documentation.
Choose a strategy from the evidence
Match the control to the bottleneck
Strategy
Best fit and tradeoff
Provisioned concurrency
Protect a measured, latency-sensitive baseline or known peak. Allocated capacity costs money; excess traffic can spill over to on-demand environments.
SnapStart
Reduce substantial initialization in an eligible function. Check runtime and feature limits, restored-state safety, and caching and restore charges.
Lean initialization
Remove imports, layers, or setup work that dominates startup. Lazy loading shifts work to the first request that needs that feature.
Runtime or memory tuning
Address a measured CPU or runtime bottleneck. Memory changes affect cost; runtime changes can add migration and maintenance work.
Connections and extensions
Reduce visible first-use or extension overhead. Preserve private access, observability, and safe connection recovery.
Scheduled warm-up
Only a measured best-effort reduction for noncritical traffic. It adds recurring invocation cost and does not guarantee capacity.
Estimate the bill for the whole control
Compare PC's allocated-capacity charge and invocation charges with the latency benefit for the actual schedule. SnapStart has its own runtime-dependent caching and restore rules. Memory and extension changes affect normal execution charges. Use current AWS pricing for the chosen Region and configuration rather than carrying over a flat “low cost” label.
Verify the user-visible result
Repeat tests after changes with the same function version, traffic shape, downstream services, and logging configuration. Compare cold-start fields, end-to-end latency percentiles, errors, spillover, and total cost. Set CloudWatch alarm thresholds from workload-specific objectives; standard-metric alarm configuration does not replace analysis of initialization logs.
Summary
Lambda cold starts come from creating and initializing execution environments. Provisioned concurrency and SnapStart change when or how Lambda initializes environments. Leaner initialization, measured runtime and memory choices, connection management, and extension review reduce work on that path. Scheduled pings may help a narrow best-effort case, but they do not guarantee reuse or burst capacity.
Start with low-cost measurements
Inspect Init Duration in logs and separate it from handler and downstream latency.
Remove unnecessary imports, layers, setup calls, and extensions.
Benchmark memory and runtime changes instead of relying on generic language rankings.
Choose managed startup controls when the requirement needs them
Use SnapStart if the runtime, Region, and function features qualify and the code handles restored state safely.
Use provisioned concurrency for latency-sensitive capacity, route calls to the configured alias or version, and monitor spillover.
Estimate the ongoing charges and retest with traffic that resembles production.