Until the middle of 2025, the answer to this question depended on how your function was packaged, and most people had it wrong in the cheap direction. That ended on 1 August 2025. Every Lambda cold start is now billed, on every configuration, and the change is worth understanding because it moves cost onto code that runs outside your handler.
Do Lambda cold starts cost money?
Yes. The Lambda execution environment documentation states it in one line, describing the download-and-set-up steps: "in this diagram, the first two steps of downloading the code and setting up the environment are frequently referred to as a 'cold start'. You are charged for this time, and it adds latency to your overall invocation duration."
What you are charged for is the INIT phase, and the INIT phase is more than
the platform booting. AWS lists what runs in it: "start all extensions
(Extension init)", "bootstrap the runtime (Runtime
init)" and "run the function's static code (Function init)".
That third item is your import statements, your SDK clients, your database
connection pool, your model load. All of it is now billable duration at your
function's configured memory size.
The phase has a ceiling: "the Init phase is limited to 10 seconds.
If all three tasks do not complete within 10 seconds, Lambda retries the
Init phase at the time of the first function invocation with the
configured function timeout."
What changed for Lambda INIT billing on 1 August 2025?
Before that date, one configuration got the INIT phase for free. AWS's announcement, AWS Lambda standardizes billing for INIT Phase, published 29 April 2025, is explicit:
"Effective August 1, 2025, AWS will standardize billing for the initialization (INIT) phase across all AWS Lambda function configurations. This change specifically affects on-demand invocations of Lambda functions packaged as ZIP files that use managed runtimes, for which the INIT phase duration was previously unbilled."
Everything else was already paying. AWS: "functions configured with custom runtimes, Provisioned Concurrency (PC), or OCI packaging already included the INIT phase duration in their Billed Duration."
| Configuration | INIT billed before 1 Aug 2025 | INIT billed now |
|---|---|---|
| On-demand, ZIP, managed runtime | No | Yes |
| Custom runtime | Yes | Yes |
| Container (OCI) packaging | Yes | Yes |
| Provisioned Concurrency | Yes | Yes |
AWS shows the difference as a pair of log lines. Before, for a function whose INIT took 100.77 ms: "REPORT RequestId: xxxxx Duration: 250.06 ms Billed Duration: 251 ms Memory Size: 1024 MB". After: "REPORT RequestId: xxxxx Duration: 250.06 ms Billed Duration: 351 ms Memory Size: 1024 MB". Same function, same work, a hundred extra milliseconds on the meter.
Lambda@Edge is included, at its own rates: "for AWS Lambda@Edge functions, the INIT phase duration will be billed according to Lambda@Edge duration rates."
How much of a Lambda bill is cold start time?
For most workloads, very little, and AWS says so rather than hiding it: "most users will see minimal impact on their overall Lambda bill from this change, as the INIT phase typically occurs for a very small fraction of function invocations." The supporting figure, from the execution environment guide: "cold starts typically occur in under 1% of invocations. The duration of a cold start varies from under 100 ms to over 1 second."
Under 1% of invocations paying an extra sub-second is a rounding error on a high-traffic API, and a step change on a single date is exactly the shape a cost monitor is built to surface: AWS Budgets vs Cost Anomaly Detection. The picture inverts for two patterns:
- Low-traffic functions. AWS notes that "cold starts are typically more common in development and test functions than production workloads. This is because development and test functions are usually invoked less frequently." A function invoked a handful of times an hour can cold start on a large share of its invocations, so its INIT time is a large share of its bill.
- Heavy initialization. A function that loads a large dependency tree or an ML model can spend seconds in INIT and milliseconds in the handler. Its billed duration is now dominated by code that runs before the handler is even called.
Both are the same trap in different clothes: the invocation count you would use to estimate cost is not the number that drives it. Estimate on cold start rate multiplied by INIT duration, and only then compare to handler time.
How do you see the INIT duration for a Lambda function?
It has been in your logs the whole time. Every cold start's REPORT
line carries an Init Duration field, and AWS points at it: "you
can already monitor the time spent in the INIT phase of your function
invocations through the 'REPORT RequestId' log line within CloudWatch Logs,
which includes the 'Init Duration' value. Alternatively, if
Lambda Insights
is enabled, you can use the 'init_duration' CloudWatch metric."
AWS also publishes a CloudWatch Logs Insights query to size the change against your own functions. The three fields it computes:
| Field | What AWS says it is |
|---|---|
BilledGBs | "Represents the total GB-s (gigabyte-seconds) currently being billed for the chosen log groups." |
UnbilledInitGBs | "Shows the total GB-s consumed during INIT phase that was previously not included in billing." |
Ratio | "Indicates the percentage of total GB-s attributed to previously unbilled INIT phase duration." |
That query is worth running once per busy function rather than across every log group at once, because Logs Insights bills per GB scanned and a wide sweep over months of Lambda logs is its own charge. The mechanics are in what CloudWatch Logs actually cost.
One reading trap. When an invocation fails and Lambda re-initializes, the extra INIT is folded into the reported duration with no separate line: "when suppressed inits occur, Lambda doesn't explicitly report an additional INIT phase in CloudWatch Logs. Instead, you might notice that the duration in the REPORT line includes an additional INIT duration + the INVOKE duration." A REPORT line whose duration cannot be reconciled against the START and END timestamps is usually this.
Does provisioned concurrency remove the INIT charge?
It moves it, and adds a second meter on top. Provisioned concurrency pre-initializes environments, so the INIT no longer lands in front of a user's request, but the Lambda pricing page is clear that you now pay for the standby: "you pay for the amount of concurrency you configure, and for the period of time you configure it. When Provisioned Concurrency is enabled and executed for your function, you also pay for Requests and Duration."
And the initialization does not happen only once. The same page: "for functions configured with Provisioned Concurrency, AWS Lambda periodically recycles the execution environments and re-runs your initialization code." Provisioned concurrency buys predictable latency. It is not a way to stop paying for INIT.
It does change one limit in your favour. The 10-second INIT ceiling "doesn't apply to functions that are using provisioned concurrency, SnapStart, or Lambda Managed Instances. For provisioned concurrency, SnapStart, and Managed Instances functions, your initialization code can run for up to 15 minutes."
Does SnapStart reduce Lambda cold start cost?
It can, by not running INIT repeatedly. AWS describes SnapStart as eliminating the repeat: "when it's enabled, SnapStart creates a snapshot during the first function INIT and reuses it for subsequent cold starts, eliminating the need for repeated INIT phase executions." On a function with a heavy dependency load, that removes the expensive part of every cold start after the first.
Two constraints decide whether it applies to you. It is language-limited: "SnapStart is supported for Java, .NET, and Python runtimes." And the restore path is not free of charges either: "you are charged for the duration of after-restore runtime hooks", which must "complete within the timeout limit (10 seconds)."
Do you pay when a Lambda function crashes during INIT?
Yes, and AWS gives the arithmetic in a worked example. For a function that timed out, the log reads: "REPORT RequestId: b70435cc-261c-4438-b9b6-efe4c8f04b21 Duration: 3004.92 ms Billed Duration: 3117 ms Memory Size: 128 MB Max Memory Used: 33 MB Init Duration: 111.23 ms". The billed duration exceeds the run duration by roughly the init duration. A function that fails is billed for the environment it built before failing.
When the failure is inside INIT itself, Lambda emits a separate record:
"if a function crashes or times out during the Init phase, Lambda
emits error information in the INIT_REPORT log", of the form
"INIT_REPORT Init Duration: 1236.04 ms Phase: init Status: timeout". A function
crash-looping on a bad dependency import is therefore a repeating charge, and
a silent one: "if the Init phase is successful, Lambda doesn't
emit the INIT_REPORT log unless SnapStart or provisioned
concurrency is enabled", so the only time this line appears is when something
is wrong.
How do you cut Lambda INIT time?
AWS names package size as the first lever: "larger function packages increase code download times. You can decrease INIT phase duration by reducing package size, resulting in faster cold starts and lower INIT costs."
Beyond that, the decision is where code lives, and it now has a price attached:
- Keep genuinely reusable work in INIT. AWS still recommends it: use the INIT phase "to perform one-time operations that benefit subsequent invocations", such as "pre-calculating lookup tables or transforming static datasets". Work done once per environment and reused across a hundred invocations is cheaper there than in the handler, even now. Reading configuration is the everyday case, and it has a meter of its own on the other side: fetching a secret or a parameter per invocation is billed per call, and for an encrypted parameter it is a KMS request too, as Secrets Manager vs Parameter Store sets out.
- Move per-request work out of INIT. Anything that has to happen per invocation anyway gains nothing from running at import time, and now costs on every cold start.
- Import narrowly. Pulling one client out of a monolithic SDK package rather than importing the whole thing cuts both download and initialization.
- Check the free tier before optimising at all. The pricing page states it as "one million requests and 400,000 GB-seconds per month". A function under that is optimising nothing.
Where does INIT duration appear on a Lambda bill?
Nowhere separate, and that holds whatever invokes the function: a Lambda
behind an API Gateway endpoint
pays the gateway's per-request charge and this duration charge as two
unrelated lines. INIT duration is folded into the same duration meter as
handler execution, so there is no INIT usage type to filter on in the CUR and
no line item that says "cold start". The only place the split is visible is
the Init Duration field in your logs, which is why the Logs
Insights query above is the entire measurement story.
That also makes per-team attribution of Lambda spend a tagging problem rather than a metering one, with the same failure modes as everything else that bills per resource. If your Lambda costs are not splitting by team, the cause is usually one of the ones in why cost allocation tags show up empty, not anything specific to Lambda.