Once an organisation has seen what idle virtual machines cost, the natural reaction is to swing to the opposite pole. If paying for servers that sit idle is the problem, why not pay only when code actually runs? Serverless functions promise exactly that: no servers to manage, no idle capacity, and a bill that tracks real use.
For the right workload, that promise holds, and the savings can be dramatic. For the wrong workload, serverless can cost more than the virtual machine it replaced, and take more engineering effort to run well. The difference is not about how modern the technology is. It is about the shape of the demand, the way the work behaves, and what the team can operate.
This part is about choosing a runtime on those grounds rather than on fashion.
Bushbuck Brands is fictional, and its systems and figures are illustrative. Bushbuck, the South African FMCG distributor in this series, classified its remaining applications in Part 3. Twenty were marked for replatforming, which raised the question this part answers: replatform onto what?
Three runtime families, three strengths
At the level that matters for a cost decision, there are three broad families of runtime.
Serverless functions and event-driven managed services run code in response to an event (a file arriving, a message on a queue, an HTTP request) and are billed for the work done. They remove idle runtime and most operational work: there is no operating system to patch and no cluster to size. They are strongest for event-driven, bursty and stateless work.
Containers package an application with its dependencies so that it runs the same way everywhere. They can run on a managed application platform, a serverless container service, or a Kubernetes cluster. They are useful when packaging consistency and runtime control matter: long-running services, specific libraries, steady traffic, or a team that wants the same artefact in development and production.
Virtual machines remain appropriate for supported legacy software and predictable workloads: vendor products that are supported only on a particular operating system, software with licensing tied to cores or hosts, and steady services where a right-sized, committed VM is simply the cheapest way to run them.
None of these is the "cloud native" answer. Each is the right answer for some workloads and an expensive answer for others.
Start from the shape of demand
The most useful single input to a runtime decision is a picture of the workload's demand over a day, a month and a year.
| Workload shape | Starting candidate |
|---|---|
| Bursty events and short execution | Functions or event-driven managed services |
| Scheduled batch, idle between runs | Scheduled container jobs or a batch service |
| Web API with variable demand | Managed application platform or containers |
| Long-running predictable service | Containers, managed runtime or committed VMs |
| Vendor application with OS dependency | Virtual machines or an approved hosted product |
| Commodity business capability | SaaS comparison before custom hosting |
These are starting candidates, not rules. The demand shape narrows the choice; the team's operating capability and the service level settle it.
How serverless is actually billed
To decide well, it helps to know what the meter is measuring. The details differ by provider, but the mechanics are similar.
- AWS Lambda charges per request and for the duration the code runs, measured in GB-seconds (memory allocated multiplied by time), rounded to the millisecond.
- Azure Functions on the Flex Consumption plan bills on-demand execution time and the number of executions; if you configure "always ready" instances to avoid cold starts, a baseline charge applies to those instances even when they are idle.
- Google Cloud Run offers request-based billing, where you pay only while instances are processing requests (and starting or shutting down), and instance-based billing, where you pay for the whole life of each instance whether or not it is busy.
Two consequences follow. First, cost tracks requests multiplied by duration multiplied by memory. A function that is called rarely and finishes quickly is very cheap; one that is called constantly and waits on a slow database is not. Second, every technique for keeping a function warm reintroduces idle cost. Always-ready instances, minimum instances and instance-based billing are useful, but they move the service back towards paying for capacity rather than work.
The five ways serverless costs rise
Serverless costs can rise quietly, through behaviours that were invisible on a virtual machine:
- High request volume. Per-request charges are tiny until there are hundreds of millions of them. A steady, heavy API may cost less on a container that serves many requests per instance.
- Long execution. Duration is billed. A function that spends most of its time waiting for a slow downstream system is paying to wait.
- Excessive logging. Functions make it easy to log everything, and log ingestion and retention are billed separately. At Bushbuck's volumes, logs for one chatty function would have cost more than the function.
- Inefficient data access. Each invocation that opens a new database connection, re-reads reference data or makes several small calls instead of one adds duration and load on the database, which may then need to be larger.
- Repeated cold starts. When a function has not run for a while, the platform has to start a new instance. For a latency-sensitive API, the usual fix is to keep instances warm, which, as above, brings back idle cost.
None of these makes serverless a bad choice. They make it a choice that needs the same discipline as any other: measure the demand, design the data access, and set logging by purpose.
Bushbuck's three decisions
Bushbuck applied this to three workloads, with three different answers.
Nightly route planning: the clear win. The route planning engine calculated the next day's deliveries for all three distribution centres. It ran for about 90 minutes each night on two large virtual machines that were billed for all 24 hours. Bushbuck replatformed it as a scheduled container job that starts at 01:00, scales out to finish faster, and stops. It is now billed for a couple of hours of compute a night instead of 48 machine-hours. The code changed very little; the runtime model changed completely.
Proof-of-delivery uploads: a natural fit for functions. Drivers' handheld devices upload a photo and signature for each delivery. Uploads arrive in bursts as trucks come back into signal. A small function that validates each upload, stores it and records it against the delivery is billed per event, sits idle at no cost overnight, and needs no server to manage.
The EDI order API: containers, after a spike. Supermarket chains send orders to Bushbuck through an EDI API. Demand varies through the day but never drops to zero, and each order involves several long calls to the pricing database. The team ran a two-week spike comparing functions with a managed container platform. On compute alone, functions looked cheaper. Once everything else was counted, the answer reversed.
Compare the complete service cost
The cheapest compute line is not necessarily the lowest-cost service. A fair comparison includes everything it takes to run the service well for its life:
- Engineering: the effort to build or adapt it for the runtime, including rework for limits such as execution timeouts or connection handling.
- Operations: monitoring, scaling, patching (if any), and on-call effort.
- Security: identity, network controls, secrets and vulnerability management for the runtime.
- Backup and resilience: what has to be added to meet recovery and availability requirements.
- Support: who can support it, and how scarce those skills are.
- Change effort: how hard it is to change the service safely next year.
For the EDI API, functions needed always-ready instances to meet the chains' response-time expectations, generated heavy logs at high request volumes, and needed rework to handle long database calls within execution limits. Managed containers carried a higher compute line and somewhat more operations work, but cost less as a whole service, and the team already knew how to run them. Bushbuck chose containers. On a different workload, the same comparison could just as easily point the other way.
Kubernetes before you need it
Containers raise a related trap. A small team that adopts Kubernetes before it needs cluster-level control can create an expensive platform burden: cluster upgrades, networking, ingress, security policy, observability and capacity planning, all before the first business feature ships. Managed Kubernetes services reduce some of that work but do not remove it.
For most organisations of Bushbuck's size, a managed application platform or serverless container service gives the benefits of containers without running a cluster. Kubernetes earns its cost when many teams need a shared platform with consistent control, which is the argument our piece on the case for platform engineering makes in more depth. Bushbuck's 22-person IT team did not need it, and decided not to build it.
Cloud native is not a billing category
The phrase "cloud native" is often used as though it were a cost strategy. It is not. A cloud-native design can be cheap or expensive; a virtual machine can be the most economical choice in the estate. What matters is whether the runtime matches the demand shape, the operating capability and the service level, measured as the complete cost of running the service.
Common mistakes
- Choosing serverless because it sounds modern. Choose from the demand shape and the complete service cost.
- Comparing only compute prices. Engineering, operations, logging, security and support often decide the answer.
- Keeping functions warm without counting the cost. Always-ready and minimum instances bring idle charges back.
- Leaving default logging on high-volume functions. Log by purpose, sample where you can, and set retention.
- Adopting Kubernetes for a handful of services. A managed platform usually delivers the benefit without the burden.
- Assuming VMs are always the legacy option. For steady, licensed or vendor-bound workloads, a right-sized committed VM may be the cheapest service.
A decision you can defend
We will run Bushbuck's EDI order API on a managed container platform rather than functions, because a two-week spike showed that, once always-ready instances, logging, rework for long database calls, operations and support were counted, containers cost less as a complete service and the team can already operate them. We accept a higher compute line and more operational work than functions would need. We will review the choice if order volume or the pricing database's response times change materially, or after twelve months of production data.
What to take from this part
Match the runtime to the shape of demand. Bursty and short suits functions; steady and heavy often suits containers or committed VMs.
Serverless is billed on requests, duration and memory. Keeping it warm brings idle cost back.
Five behaviours raise serverless costs. Volume, long execution, logging, data access and cold starts.
Compare the complete service cost. The cheapest compute line is not the cheapest service.
Next in the series: FinOps starts before deployment.
How CloudNala can help
We help teams choose runtimes from evidence: profiling the demand shape, running short spikes that compare complete service cost rather than compute price, and recommending a managed platform or Kubernetes only where the team and the workload justify it.
Work with CloudNala
CloudNala helps organisations move from technology ambition to practical execution across cloud, AI, data, platform engineering and digital services.
Whether you are exploring AI, modernising your cloud environment, building a public-sector digital service, or turning an idea into a working MVP, we can help you shape the roadmap and deliver the next step.
Request a Cloud Review or write to us at consult@cloudnala.co.za