Introduction
Ah, Lambdas. Probably my favorite AWS service! Almost instantly, they allow you to create a small script or even a fully hosted API backend in the Cloud, all at a low cost thanks to the “pay-as-you-go” model. But is it too good to be true?
A few days ago, AWS announced a change in how the Lambda initialization phase is billed. Starting August 1, 2025, this phase will systematically be included in the billed duration calculation, for all Lambdas.
If you weren’t aware, until now, if you used Lambda functions packaged as ZIP archives with AWS-managed runtimes (like Python, Node.js, etc.), the duration of this INIT
phase wasn’t billed. It was a small “gift” from AWS (quite nice of them). But all good things must come to an end, and we will now have to pay for this initialization time for our Lambdas.
So, will this make using Lambdas too expensive? And how can we minimize this initialization part as much as possible? Today, let’s explore these questions!
Understanding the Lambda Lifecycle
Before diving into billing, it’s a good opportunity to recall the Lambda lifecycle.
For simplicity, I won’t go into the details of Lambda Extensions and Lambda SnapStart.
It consists of three main phases:
- INIT: This is the “cold start” phase. When a new instance of your function needs to be created to handle a request, Lambda prepares the environment. This phase lasts a maximum of 10 seconds.
- INVOKE: This is where your code (the function handler) is executed to process the request.
- SHUTDOWN: When the execution environment hasn’t been used for a certain period, the Lambda shuts down to free up resources. If a new request arrives, the Lambda will have to go through the INIT phase again.
During the INIT
phase, your Lambda performs several actions:
- Retrieves your code (from S3 for a ZIP, or ECR for a Docker image).
- Configures the environment with the allocated memory, chosen runtime, etc.
- Starts the runtime (
Runtime INIT
). - Executes the static code of your function (everything outside the handler, like initializing global variables or
boto3
) (Function INIT
).
The key takeaway here is that the INIT
phase only occurs during a cold start. If a request arrives while an execution environment is already “warm” (ready and reused), this phase is skipped, and execution goes directly to the INVOKE
phase. This is called a “warm start,” which is much faster.
AWS doesn’t disclose its logic for transitioning a Lambda from ‘warm’ to ‘cold’.
The Billing Change in Detail
Currently, Lambda billing is based on two factors:
- The number of requests.
- The execution duration of your code, rounded up to the nearest millisecond (the cost of this duration depends on the memory allocated to the function).
Until August 1, 2025, for functions packaged as ZIPs with managed runtimes, the INIT
phase duration was not counted in the “Billed Duration”. This could be seen in CloudWatch logs:
|
|
As you can see, AWS will now take your Init Duration into account in addition to the Duration when calculating the Billed Duration.
What Impact on the Bill?
So, this all sounds interesting, but will this change break the bank?
Let’s take an example to see more clearly. Imagine a Python Lambda configured with 1024 MB of memory, deployed in the eu-west-1
(Ireland) region.
Assume the following:
- The Lambda receives 10 million invocations per month.
- The cold start rate is 1% (average provided by AWS), meaning 100,000 cold starts per month.
- The average invocation duration (
Duration
) is 3 seconds. - The average initialization duration (
Init Duration
) is 1 second. - Cost per request: $0.20 per million requests.
- Duration cost (x86): $0.0000166667 per GB-second.
Details of the calculation
Cost Calculation BEFORE August 1, 2025:
- Request Cost: 10 million req * ($0.20 / 1 million req) = $2.00
- Duration Cost:
- Warm starts (9.9 million): Billed duration = 3 seconds.
- Cold starts (100,000): Billed duration = 3 seconds (INIT not billed).
- Total billed duration (seconds): (9,900,000 * 3 s) + (100,000 * 3 s) = 29,700,000 seconds + 300,000 seconds = 30,000,000 seconds.
- Total GB-seconds: 30,000,000 seconds * (1024 MB / 1024 MB) = 30,000,000 GB-s.
- Duration Cost: 30,000,000 GB-s * $0.0000166667/GB-s = $500.00
- Total Monthly Cost (Before): $2.00 + $500.00 = $502.00
Cost Calculation AFTER August 1, 2025:
- Request Cost: $2.00 (unchanged)
- Duration Cost:
- Warm starts (9.9 million): Billed duration = 3 seconds.
- Cold starts (100,000): Billed duration = 3 seconds (
Duration
) + 1 second (Init Duration
) = 4 seconds. - Total billed duration (seconds): (9,900,000 * 3 s) + (100,000 * 4 s) = 29,700,000 seconds + 400,000 seconds = 30,100,000 seconds.
- Total GB-seconds: 30,100,000 seconds * (1024 MB / 1024 MB) = 30,100,000 GB-s.
- Duration Cost: 30,100,000 GB-s * $0.0000166667/GB-s = $501.67
- Total Monthly Cost (After): $2.00 + $501.67 = $503.67
In this specific scenario, the increase is only $1.67 per month. This is indeed minimal and confirms AWS’s communication. But be careful, as the actual impact will strongly depend on:
- The memory allocated to your Lambdas (more memory = higher cost per ms).
- The actual duration of your
INIT
phase. - Your cold start rate (can be higher if your traffic is irregular).
Therefore, it’s wise to check with your own numbers!
Below is a small script that will allow you to quickly test this on your side.
Python Script
|
|
How to Monitor Your INIT Phase and Estimate the Impact?
A script is nice, but if you have a bunch of Lambdas to check, you might find the task exhausting.
Fortunately, AWS provides some tools to check this efficiently. As seen earlier, each Lambda will generate a REPORT
log containing its Init Duration
. We can easily aggregate this information using CloudWatch Logs Insights. And the icing on the cake, AWS even provides us with the right query.
|
|
Keep in mind that CloudWatch Logs Insights is billed at $0.005 per GB of data scanned (source). Adjust the query time range to limit costs.
Just run this query on your Lambda log groups (using the /aws/lambda
prefix or specific function prefixes), and you’ll get a result like this:
BilledGBs | UnbilledInitGBs | Ratio |
---|---|---|
512.8007 | 86.6699 | 0.1446 |
This query gives you three key pieces of information:
BilledGBs
: The total GB-seconds currently billed.EstimatedInitGBs
: The total GB-seconds consumed during theINIT
phase that were not previously billed (this is an estimation based on the difference between current billed duration and potential future billed duration includingINIT
).EstimatedInitCostPercent
: The percentage that these previously unbilledINIT
GB-seconds represent compared to the total consumed GB-seconds (current billed + estimated init). This approximates the potential percentage increase in your duration costs due to the change.
In our example, the cost share of the INIT
phase represents approximately 14% of the total execution cost (current + potential init cost)! Depending on your current bill, this could be significant.
Understanding and Optimizing Your Lambda
Okay, so you know you might have to pay more. But aren’t there levers we can pull to reduce this increase in your bill?
Here are some tips for making the best use of this INIT phase and thus reducing your future costs.
Strategically Use the INIT Phase
Your first instinct might be to remove all the INIT
code (code outside the handler) and put it in your handler. That way, no more INIT
billing! But not only would you just be shifting the problem (because executing that code will still be billed), it would be even worse, because now even your ‘warm start’ Lambda executions would have to process this code!
Yes, remember that the code in the INIT
phase is executed only during cold starts. Therefore, it’s the ideal place for expensive initialization operations that can be reused by subsequent (“warm start”) invocations. This is even recommended by AWS. Thus, the INIT
phase is perfect for:
- Importing heavy libraries or dependencies.
- Establishing connections to other AWS services (S3, DynamoDB, etc.) via SDKs (
boto3
for Python). - Creating database connection pools.
- Fetching parameters or secrets from Systems Manager Parameter Store or Secrets Manager.
Maximize this initialization phase to reduce the execution time of Lambdas running in ‘warm start’.
Optimize Package Size
This is often the simplest lever, because sometimes we import all sorts of things into our Lambda. So, make sure to include only strictly necessary dependencies. Also, be sure to exclude anything related to your development environment (I can’t tell you how many times I’ve found a node_modules
or tests
folder in Lambdas…). Finally, don’t hesitate to consult AWS articles, as some directly tackle the subject of cold starts.
Lambda SnapStart
Available for Java, .NET, and Python runtimes, SnapStart is a very interesting feature for combating cold starts. When you enable it, Lambda takes a “snapshot” of the initialized execution environment after the first INIT
phase. For subsequent cold starts, Lambda restores this snapshot instead of redoing the entire INIT
phase, saving you significant time.
I imagine reading about this feature, you’re thinking “Wow, this is great, I’m going to enable this feature on all my Lambdas!”. Except there are a few subtleties to be aware of.
Firstly, SnapStart is currently only compatible with specific versions of certain languages (Python 3.12 minimum, NodeJS not supported…). The same goes for regions; only a limited number support this feature at the time of writing. Finally, this feature is not free and incurs its own costs. Make sure to check the potential cost if you want to enable it on your Lambdas.
Provisioned Concurrency
If your application has predictable traffic or if cold start latency is unacceptable, you can use “Provisioned Concurrency”. You ask Lambda to keep a certain number of execution environments pre-initialized (warm) at all times.
Advantage: Requests hitting these provisioned instances never experience a cold start. The INIT
phase is done upfront, before the first request.
Disadvantage: You pay for the time these environments are provisioned, whether they receive requests or not. The INIT
phase is also billed during this pre-initialization.
Here too, it’s up to you to see if it’s worth enabling this on some of your key Lambdas!
Conclusion
The upcoming change in billing for Lambda’s INIT
phase on August 1, 2025, is primarily a standardization. For the majority of Lambdas (specifically those using managed runtimes and ZIP packaging that previously benefited from the free init), this means the duration of this phase will now be added to the billed duration during cold starts.
Even if the financial impact will likely be small for you, it’s an excellent opportunity to:
- Understand your Lambda’s lifecycle and what happens during initialization.
- Measure the
INIT
phase duration of your critical functions using CloudWatch tools. - Optimize this phase if necessary, by reducing package sizes, using SnapStart, or considering Provisioned Concurrency for specific use cases.
So, don’t wait until August! Familiarize yourself with CloudWatch Logs Insights now. This will allow you to identify which Lambdas to optimize first and avoid any nasty surprises on your AWS bill.