,

Serverless and Managed Service Cost on AWS, Azure and GCP (Cloud FinOps Series, Part 16)

Two near identical functions, twenty times the cost. Billing granularity, not the published rate, decides what short serverless functions cost, and concurrency moves the number further than any platform choice.

Cloud FinOps Series · Part 16 of 20

A team once showed me two functions doing almost identical work, one on AWS and one on Azure, and the Azure one cost roughly twenty times more per month. Nobody had made a mistake. The functions each ran for about 50 milliseconds, and one platform bills you for 50 milliseconds while the other bills you for a full second whether you use it or not.

TL;DR

Serverless billing looks precise because it is quoted per invocation and per gigabyte second. The precision is real but the granularity is not uniform, and for short functions the granularity, not the rate, sets your bill.

AWS Lambda bills duration in 1 millisecond increments. Cloud Run rounds billable instance time up to the nearest 100 milliseconds. Azure Functions Flex Consumption has a minimum billable execution period of 1,000 milliseconds and rounds to 100 milliseconds after that. On a 50 millisecond function those three rules produce wildly different invoices from very similar published rates.

The verdict for this part: before you compare platforms or argue about rewriting anything, measure your actual duration distribution and your requests per instance. Concurrency and duration move serverless cost far more than the price per gigabyte second ever will.

Who this is for: The assumed starting point is that you can read a cloud bill (Part 4), allocate spend to a team (Part 5), and have worked through unit economics (Part 10) and container cost (Part 15). No serverless experience is assumed. Function, invocation, cold start, gigabyte second, billing granularity, concurrency, provisioned or always ready capacity, and managed service are each defined the first time they appear.

What you are actually paying for when there is no server

Definitions first, because serverless conversations go wrong when people use the same words for different billing objects. A function is a unit of code the platform runs on demand. An invocation is one execution of that function, triggered by an HTTP request, a queue message, a file upload or a timer. A cold start is the extra latency when the platform has to create a fresh execution environment because none was warm. A gigabyte second is one gigabyte of memory held for one second, and it is the currency almost every serverless platform bills duration in. Billing granularity is the increment your measured duration gets rounded up to before you are charged. A managed service is anything where the provider runs the software for you and charges by consumption rather than by machine, which covers the queues, databases and API gateways sitting either side of your functions.

Every serverless bill is then built from the same three inputs multiplied together, plus a request fee bolted on the side. You pay for the number of invocations, the duration of each one after rounding, and the memory or vCPU you configured. AWS Lambda charges 0.20 US dollars per million requests and 0.0000166667 US dollars per gigabyte second for on demand invocations at the standard x86 rate. Cloud Run charges 0.40 US dollars per million requests plus separate per vCPU second and per gibibyte second rates. Azure Functions Flex Consumption charges per execution and per gigabyte second with a monthly free grant of 250,000 executions and 100,000 gigabyte seconds per subscription.

Look at those rates side by side and they seem close enough that platform choice should be a rounding error. That intuition is wrong, and the reason is the one input nobody puts on a pricing slide. The rate applies to duration after rounding, and the rounding rules differ by three orders of magnitude between platforms. This is where the allocation clarity from Part 5 stops being enough on its own, because the tag on a function tells you who owns it and tells you nothing about why it costs what it does.

flowchart LR
  I[Invocations per month] --> B[Billed units]
  D[Measured duration] --> R[Round up to billing granularity]
  R --> F{Is it under the minimum billable period}
  F -->|Yes| M[You pay the floor, not the duration]
  F -->|No| A[You pay the rounded duration]
  M --> G[Gigabyte seconds]
  A --> G
  MEM[Configured memory or vCPU] --> G
  G --> B
  B --> C[Monthly serverless bill]
Two of these boxes are on the pricing page. The rounding box is the one that decides your invoice.

Billing granularity decides the economics of short functions

AWS moved Lambda to 1 millisecond billing granularity in December 2020, and it means what it says: a function that runs for 47 milliseconds is billed for 47 milliseconds. Cloud Run charges for resources rounded up to the nearest 100 milliseconds of billable instance time. Azure Functions documentation is explicit that the minimum billable execution period in Flex Consumption is 1,000 milliseconds, after which billing rounds up to the nearest 100 milliseconds.

Now consider what most people actually deploy. A function that validates a token, writes a row, transforms a payload or resizes a thumbnail finishes in tens of milliseconds. That is the modal serverless workload, and it is precisely the workload where a 1,000 millisecond floor multiplies your bill by twenty while the published rate stays reassuring.

PlatformDuration granularityMinimum billable periodRequest or execution feeMonthly free grant
AWS Lambda1 millisecondNone0.20 USD per million1M requests, 400,000 GB seconds
Google Cloud Run, request based100 millisecondsNone on services0.40 USD per million2M requests, 180,000 vCPU seconds, 360,000 GiB seconds
Google Cloud Run, instance based and jobs100 milliseconds1 minute per instance lifetimeNot charged separately240,000 vCPU seconds, 450,000 GiB seconds
Azure Functions Flex Consumption100 milliseconds after the floor1,000 millisecondsPer execution, see pricing page250,000 executions, 100,000 GB seconds, on demand only

Granularity, floors and free grants read from the AWS Lambda pricing page, the Cloud Run pricing page and Microsoft Learn in July 2026. Free grants for Cloud Run are quoted at us-central1 rates and are aggregated per billing account. Azure always ready instances carry no free grant at all.

Work the arithmetic on a single realistic workload and the spread stops being theoretical. Take 10 million invocations a month of a function with 512 megabytes of memory that runs for 50 milliseconds. On Lambda the request fee is 2.00 US dollars and the duration is 250,000 gigabyte seconds, which at 0.0000166667 US dollars comes to about 4.17 US dollars, so roughly 6.17 US dollars before any free tier. On Flex Consumption the same 50 millisecond function is billed as a full second, so 5 million gigabyte seconds rather than 250,000, and the bill lands two orders of magnitude higher on the duration component. Same code, same memory, same traffic.

Same function, four billing modelsEstimated monthly cost, 10 million invocations of a 50 millisecond function at 512 MB.03570105140USD per month4.636.1729.25134Cloud Runconcurrency 20AWS Lambda1 ms granularityCloud Runconcurrency 1Azure Flex1,000 ms floorThe red bar is not a worse platform. It is the same platform meeting a workload it was not priced for.Arithmetic from published July 2026 rates. Cloud Run modelled at 1 vCPU and 512 MiB, request based billing.
A 29 times spread from rates that all look within a few percent of each other on the pricing pages.

Gotcha

The granularity penalty vanishes as functions get longer, and that is the part people forget when they turn this into a platform war. Take the same 10 million invocations at 512 megabytes but let each run for 2 seconds instead of 50 milliseconds. Every platform is now well past every floor, the rounding is irrelevant, and the gap between the cheapest and the dearest collapses from roughly 29 times to under 2 times.

So the honest statement is narrower than the headline. Billing floors punish short functions specifically. If your median duration is comfortably above one second, granularity is not your problem and you should go and look at memory sizing and concurrency instead.

Concurrency is the lever nobody configures

Concurrency here means the number of requests one instance handles at the same time. It is the single biggest structural difference between the platforms and it is almost never in the comparison spreadsheet. Lambda is fixed at one invocation per execution environment, so your cost scales linearly with invocations and there is nothing to tune. Cloud Run lets you set concurrency per instance, and the pricing page states plainly that when concurrency is higher than one, multiple requests share the allocated CPU and memory of an instance. Azure Functions Flex Consumption exposes configurable concurrency per function too, with per function scaling built into the platform.

The consequence is arithmetic. If twenty requests share one instance, you are billed for one instance second rather than twenty request seconds, so the compute component of your bill divides by roughly twenty. In the chart above, the difference between the cheapest bar and the third bar is not two different products. It is the same Cloud Run service with concurrency set to 20 instead of 1. Nothing was rewritten and no region was changed.

In practice teams end up at concurrency 1 for two reasons, and only one of them is legitimate. The legitimate reason is that the code is not thread safe or holds per request global state, in which case concurrency 1 is correct and the cost is the price of correctness. The illegitimate reason, which I see far more often, is that concurrency 1 was the default in whichever tutorial the service was copied from, and nobody has revisited it since. Checking that single setting across a fleet of services is an afternoon of work and it is routinely the highest return activity in a serverless cost review.

Idle capacity comes back wearing a different name

The pitch for serverless is that you stop paying for idle. Then cold starts hurt a latency target, someone enables warm capacity, and idle walks straight back onto the invoice under a new label. Lambda calls it provisioned concurrency. Cloud Run calls it minimum instances. Azure Functions Flex Consumption calls it always ready instances. All three are the same trade: you pay for capacity that is not serving anything so that the capacity is there when traffic arrives.

What differs is how brutally each one is priced, and Cloud Run is unusually generous here in a way that is worth knowing. Under request based billing, active CPU costs 0.000024 US dollars per vCPU second while idle CPU on a minimum instance costs 0.0000025 US dollars per vCPU second. Idle CPU is roughly a tenth the price of active CPU, which makes keeping a couple of instances warm remarkably cheap insurance against cold starts. Memory is charged at the same rate whether active or idle, so the saving applies to the CPU component only.

Azure runs the opposite policy and states it clearly. Always ready instances are billed on the memory provisioned across the baseline, plus memory during active execution, plus executions, and there are no free grants in always ready billing at all. Enabling one always ready instance therefore moves that function out of the free tier entirely, which is a discontinuity worth planning for rather than discovering.

There is one more asymmetry that catches commitment planning. AWS applies automatic tiered discounts to Lambda on demand compute duration, 10 percent above 6 billion gigabyte seconds a month and 20 percent above 15 billion on x86, with the thresholds set at 7.5 billion and 18.75 billion on arm64. Those discounts apply to on demand duration only and explicitly do not apply to provisioned concurrency. Lambda also participates in Compute Savings Plans, so the commitment logic from Part 12 extends to serverless rather than stopping at instances, and the two mechanisms stack.

Managed services send you a second bill

A function almost never runs alone. It sits behind an API gateway, reads from a queue, writes to a managed database and emits logs, and every one of those is metered separately. In a serverless architecture the compute line is frequently the smallest number on the page, which is disorienting the first time you see it because compute is the thing everyone optimised.

Google documents this pattern honestly on its own pricing page. Cloud Run notes that deploying from source uses Cloud Build and stores images in Artifact Registry, that pricing for both sits outside Cloud Run pricing, and that exceeding the Artifact Registry free tier can produce charges for deploying your functions even when the Cloud Run usage itself is inside the free tier. Event delivery through Eventarc is billed separately again. None of that is hidden, and all of it is invisible if you only read the compute page.

The practical failure is one I have watched play out repeatedly. A team migrates from containers to functions, reports a large compute saving, and quietly grows the API gateway, log ingestion and per request database charges past the amount they saved. Compute went down and total cost went up, and because those charges land on different service lines nobody connects them for two quarters. The reporting fix from Part 7 applies directly here: report serverless workloads as a whole application, gateway and logs and data included, never as a compute line on its own.

In practice

Four numbers tell you everything about a serverless workload, and none of them are on a pricing page. Median and 95th percentile duration, because the median tells you whether you are fighting a billing floor and the tail tells you what your memory sizing is really buying. Requests per instance, because that is your concurrency in the real world rather than in the config file. Ratio of compute cost to total application cost, because if compute is under a third of the bill then optimising the function is theatre. And warm capacity as a percentage of total spend, because that is the number that grows silently after every latency incident.

Pull those four for your top ten functions before you form any opinion about the architecture. In my experience roughly half of serverless cost reviews end with nothing being rewritten and two settings being changed.

Does serverless still win at high volume?

The received wisdom is that serverless is cheap at low volume and turns expensive as you scale, at which point you should move to instances or containers. The direction is right and the crossover point is usually much further out than people assume, which matters because teams rewrite things far too early on the strength of a feeling.

Work it through with the Lambda numbers already established. A 50 millisecond function at 512 megabytes costs about 0.417 US dollars per million invocations in duration plus 0.20 US dollars per million in request fees, so about 0.617 US dollars per million all in. Set that against a small always on instance costing 100 US dollars a month, and the two meet at roughly 162 million invocations, which is about 62 requests per second sustained every second of the month.

Where Lambda meets an always on instanceMonthly cost against invocation volume, 50 millisecond function at 512 MB, x86 on demand rates.03570105140USD per monthIllustrative always on instance, 100 USD per month6.1730.8561.70123.40Crossover near 162M, about 62 requests per second050M100M150M200MInvocations per monthMost services that get rewritten for cost reasons are nowhere near this line.The 100 USD reference is illustrative and excludes the availability, patching and scaling you would rebuild.
Sixty two requests per second, sustained, before one small instance starts looking cheaper on compute alone.

Two caveats keep that number honest, and they pull in opposite directions. The instance comparison flatters the instance, because one small machine holding 62 requests per second continuously has no headroom, no redundancy and nobody patching it, and once you add a second machine for availability the crossover moves out past 320 million invocations. The comparison also flatters Lambda, because a longer function moves the crossover in sharply: at 500 milliseconds rather than 50, duration cost is ten times higher and the same line is crossed near 23 million invocations a month. Duration, not volume, is what actually decides this, which is why a rule of thumb expressed in requests per second is close to useless.

Function durationLambda cost per million invocationsInvocations to reach 100 USDEquivalent sustained rate
50 milliseconds0.62 USD162 millionAbout 62 per second
200 milliseconds1.87 USD54 millionAbout 21 per second
500 milliseconds4.37 USD23 millionAbout 9 per second
2 seconds16.87 USD6 millionAbout 2 per second

Arithmetic at 512 MB on x86 on demand rates, 0.20 USD per million requests plus 0.0000166667 USD per gigabyte second, against an illustrative 100 USD per month instance. A forty times change in duration moves the crossover by twenty seven times, while volume alone moves nothing.

flowchart TD
  A{Is traffic spiky or near zero much of the day} -->|Yes| S[Stay serverless, idle savings dominate]
  A -->|No| B{Is sustained utilisation above 60 percent}
  B -->|Yes| V[Price committed instances or containers]
  B -->|No| C{Is median duration under the billing floor}
  C -->|Yes| D[Batch the work or move to finer granularity]
  C -->|No| E{Can you raise requests per instance}
  E -->|Yes| F[Raise concurrency first, measure again]
  E -->|No| G{Is compute over half of application cost}
  G -->|No| H[Optimise gateway, logs and data instead]
  G -->|Yes| V
  F --> S
  D --> S
Most paths end somewhere other than a rewrite, which matches how these reviews actually finish.

Measure duration and concurrency before you compare platforms

The recommendation for this part is deliberately unglamorous. Build a duration histogram and a requests per instance figure for your top ten serverless workloads, and refuse to have any platform, architecture or rewrite conversation until both exist. Those two measurements determine whether you are paying a billing floor, paying for unshared instances, or paying an honest price for real work, and the three situations have completely different fixes that look identical from the invoice.

Then act in this order. Raise concurrency wherever the code is thread safe, because it is free and it divides your compute bill. Right size memory next, remembering that on most platforms more memory buys proportionally more CPU, so a larger instance size can finish fast enough to cost less overall, which is the one place where the intuitive answer is backwards. Audit warm capacity third, since provisioned concurrency, minimum instances and always ready instances accumulate after incidents and nobody ever removes them. Only after all three should anyone open a document about moving off serverless.

Part 17 moves to AI and GPU spend, where the granularity problem returns in a harsher form: you are billed per token or per GPU hour, the unit is easy to read, and the relationship between that unit and business value is the hardest in this series so far. The unit economics framing comes from Part 10, the shared capacity problem was worked through for containers in Part 15, and every part is indexed on the Cloud FinOps guide.

One thing to do this week: pick your highest volume function, find its median duration, and check whether it is shorter than the minimum your platform will bill you for. If it is, you have found a multiplier rather than a percentage.

Cloud FinOps Series · Part 16 of 20
« Previous: Part 15  |  Guide  |  Next: Part 17 »

References

Rates, granularity rules and free grants were verified against AWS, Google and Microsoft documentation in July 2026 and change over time and by region. The Azure Flex Consumption per gigabyte second rate used in the comparison chart is taken from the Azure Functions pricing page and should be re-checked for your region before it is quoted in a business case [VERIFY]. All cost figures in this part are arithmetic worked from published list rates rather than figures from a live account.

About The Author


Discover more from Journal of Intelligent Infrastructure – By Dr Pranay Jha

Subscribe to get the latest posts sent to your email.

Leave a Reply

Your email address will not be published. Required fields are marked *

Architect’s Toolkit

About the Author

Dr. Pranay Jha is a Cloud and AI Consultant with 18+ years of experience in hybrid cloud, virtualization, and enterprise infrastructure transformation. He specializes in VMware technologies, multi-cloud strategy, and Generative AI solutions. He holds a PhD in Computer Applications with research focused on Cloud and AI, has published multiple research papers, and has been a VMware vExpert since 2016 and a VMUG Community Leader.

Discover more from Journal of Intelligent Infrastructure - By Dr Pranay Jha

Subscribe now to keep reading and get access to the full archive.

Continue reading