Serverless vs Containers vs Virtual Servers: What the Choice Means for Your App and Your Bill
Ask three developers where your application should run and you may hear three answers: serverless, containers, or a plain virtual server. All three can be defended. What differs is how the bill behaves, how much operational work lands on your team, and how hard it is to move later.
This guide compares the three for an owner or manager planning web application development. It quotes no prices, because list prices change. It explains what each meter counts, which matters more.
It covers only the compute choice. Shared hosting, managed platforms, backups, data location and budget alerts are in our guide to choosing cloud hosting for business applications.
The three options in plain terms
A virtual server (also called a virtual machine or VPS) is a rented computer that stays switched on. You get an operating system and install whatever the application needs. Amazon EC2, Azure Virtual Machines and Google Compute Engine are examples, as is a VPS from a smaller host.
A container is a package holding the application and everything it needs to run. With a managed container service such as AWS Fargate, Google Cloud Run or Azure Container Apps, you hand over the package and the provider runs it without giving you a server to look after.
A serverless function is a small piece of code that the platform starts when something happens, such as a web request, a file upload or a scheduled time, and stops when the work is done. AWS Lambda and Azure Functions are the best-known examples.
The labels overlap. Cloud Run is a container service, yet Google's documentation says a service that receives no traffic is, by default, scaled to zero instances. So the more useful question is whether anything is running, and being billed, when nobody is using the application.
How you are charged for each
A virtual server is billed for the time it is switched on. AWS states that an On-Demand EC2 instance is charged from the time it is launched until it is terminated or stopped, by the second with a 60-second minimum for most operating systems. The meter counts time, not work, so a quiet night costs the same as a busy afternoon and the bill is easy to predict.
A managed container service also bills for running time, but in smaller units that can be added and removed with demand. AWS Fargate pricing is based on the vCPU, memory and storage of each task, from the moment the container image starts downloading until the task ends, by the second with a one-minute minimum on Linux.
Serverless functions are billed for work done. Microsoft describes its Flex Consumption plan for Azure Functions as billed on the number of executions and the memory of instances while they are actively executing, plus the cost of any instances you choose to keep always ready (Azure Functions hosting options). Idle time costs nothing unless you pay to keep something warm.
Under all three, compute is only one line on the invoice. The database, file storage, logs and data transfer are metered separately.
What each option asks of your team
A virtual server asks the most. Someone has to apply operating system updates, configure the firewall, set up monitoring, run deployments and notice when the disk is filling up. It is ongoing work that must belong to a named person.
A managed container service removes the server but not the packaging. Your team builds the container image, keeps the software inside it up to date, and sets the scaling and networking rules. Running your own container orchestration with Kubernetes is a much heavier commitment and is rarely justified for a single application.
Serverless functions ask for the least server work and the most design work. The application has to be split into pieces that hold nothing in memory between requests, and testing and monitoring many small pieces is different from watching one application.
Cold starts and the limits of serverless functions
When a function has not run recently, the platform must prepare an environment before your code can answer. AWS calls this a cold start and explains that Lambda downloads the code, starts the environment and runs any initialization code first. Its documentation says cold starts typically occur in under 1% of invocations, last from under 100 ms to over 1 second, and are more common for functions that are invoked less often.
That last point matters for smaller businesses: a lightly used internal tool is the kind of application whose users meet cold starts most. Each provider offers a remedy, such as provisioned concurrency on Lambda, always ready instances on Azure Functions and minimum instances on Cloud Run. Each means paying for idle capacity again, which gives back part of the billing advantage.
Limits to design around
AWS lists Lambda quotas that cannot be raised for standard functions: a timeout of 15 minutes per invocation, a maximum of 10,240 MB of memory, and 6 MB each for the request and response of a synchronous call. Some newer Lambda variants have different limits, so check the current page. On Azure, the Flex Consumption plan enforces no maximum execution time, but Microsoft notes that an HTTP-triggered function has at most 230 seconds to respond, and the legacy Consumption plan caps execution at 10 minutes.
In practice, long report generation, large file uploads, video processing and connections that stay open all need either a different design, such as queues and direct-to-storage uploads, or a different home.
When a plain virtual server is the right answer
A virtual server fits when traffic is steady, when the application is a conventional one built on a framework such as Laravel or Node.js with a single database, and when the work includes long-running jobs, background workers or open connections that functions handle poorly.
It also fits when a predictable monthly figure matters more than paying the minimum in a quiet month. The condition is firm: someone competent must own patching, monitoring and restores. If nobody will, the server is the wrong choice however low the invoice looks.
Portability and lock-in
A container image is the most portable of the three. The same image can run on a virtual server, on any large provider's container service, or on a developer's laptop. A virtual server is nearly as portable, because it is a standard Linux or Windows machine.
Functions are the least portable. The code is written against one provider's event formats, triggers and permission system, and usually leans on that provider's queues, gateways and storage. Moving it is a partial rewrite, not a redeployment.
Much of the lock-in sits around the compute, not in it: a proprietary database, a messaging service, a login service. Lock-in is not automatically bad, since it is often the price of less operational work. Accept it knowingly, keep business logic separate from provider-specific code, and prefer a standard relational database.
Common mistakes
- Choosing serverless to save money on an application that is busy all day. Pay-per-use rewards idle time; with little idle time there is little to gain.
- Adopting Kubernetes for one application and one database.
- Comparing options on the compute line alone and ignoring database, storage, logging and data transfer.
- Reading "serverless" as "no operations." Your team still owns the code, access control, configuration and monitoring.
- Discovering a timeout or payload limit after launch instead of during design.
How to decide, and what to do next
Three questions settle most cases. How even is the traffic? Does any request or job run for a long time or hold a connection open? Who will operate the system once it is live?
For a typical small or mid-sized business application used steadily during working hours, a reasonable default is one container on a managed container service or managed platform, with a managed database. Choose a virtual server instead if you have an administrator and want a fixed bill. Use functions at the edges for scheduled jobs, file processing, webhooks and sudden bursts. Mixing the models is normal.
Before committing, ask your developers to write down four things:
- The expected traffic pattern across a normal week.
- The longest-running task and the largest file the application handles.
- The person responsible for updates and monitoring.
- An estimated bill for a quiet month, a normal month and a peak month, from the provider's own pricing calculator.
Conclusion
Virtual servers bill for time switched on and ask you to run the machine. Managed containers bill for running time in smaller, adjustable units and travel well between providers. Serverless functions bill for work done and remove the servers, in exchange for cold starts, hard limits and tighter ties to one provider. The right answer is usually the simplest option your team can operate reliably.
Entrant Technologies builds websites, web applications, mobile apps and custom software. If you would like a second opinion on where a planned application should run, you can share your requirements here.