Serverless vs Virtual Machines in Azure
Serverless computing and virtual machines solve fundamentally different problems. Azure Functions abstracts away the server entirely and charges per execution; a VM gives you a running operating system you configure and pay for by the hour. Choosing the wrong model wastes money or creates operational burden that adds no business value.
The two compute models
Azure Virtual Machines are Infrastructure-as-a-Service (IaaS). You provision a specific SKU, the VM runs continuously, and you pay for every hour it is allocated — regardless of whether it is processing any work. You manage the OS, runtime, patches, and scaling.
Azure Functions (Consumption plan) are Function-as-a-Service (FaaS). You write a function, deploy it, and pay only when it executes — per invocation and per GB-second of execution time. Azure manages scaling, infrastructure, and availability entirely. The first 1 million executions per month and 400,000 GB-seconds of execution time are free.
Head-to-head comparison
| Dimension | Azure Functions (Consumption) | Azure Virtual Machine |
|---|---|---|
| Billing model | Per execution + per GB-second | Per hour (regardless of utilisation) |
| Management overhead | Near zero — no OS, no patches, no scaling config | High — OS updates, agent config, scaling setup |
| Cold start latency | 200ms–2s on Consumption plan | None — VM is already running |
| Maximum execution duration | 10 minutes (default 5 min, max 60 min with Premium) | No limit — process runs indefinitely |
| State management | Stateless by default; use Durable Functions for orchestration | Stateful — in-memory state persists across requests |
| Scaling | Automatic, from 0 to hundreds of instances | Manual or VMSS autoscale with warm-up delay |
| Networking | No VNet by default; VNet integration needs Premium plan | Full VNet integration from the start |
| Custom runtime / OS | Supported runtimes only (.NET, Node, Python, Java, PowerShell) | Any OS, any runtime, any binary |
Cost model in depth
Azure Functions Consumption plan pricing (East US, as of 2026):
- Execution cost: $0.20 per million executions (first 1M free per month)
- Consumption cost: $0.000016 per GB-second (first 400,000 GB-second free per month)
Example: a function that runs 10 million times per month, takes 500ms average, and uses 256 MB memory. That is 10M executions × 0.256 GB × 0.5s = 1,280,000 GB-seconds. Cost: (9M executions × $0.20/M) = $1.80 + (880,000 GB-s × $0.000016) = $14.08. Total: approximately $16/month.
The same workload on a Standard_B1ms VM (1 vCPU, 2 GiB) at ~$15/month on pay-as-you-go is competitive. But the VM runs 24/7 whether it receives 10M requests or 100. The function scales to zero overnight at no cost; the VM does not.
The crossover point typically occurs when a workload runs at high steady throughput — say, processing millions of events per hour continuously. At that point, the per-execution billing of Functions becomes more expensive than a fixed-rate VM, and the Premium plan (which keeps instances warm) adds a base hourly charge on top of execution costs.
Azure Functions Premium plan starts at approximately $173/month (one EP1 instance pre-warmed in East US) plus consumption charges. If you need cold-start elimination and VNet integration, Premium plan is necessary — but at that point, comparing it to an App Service Plan or a VM becomes worthwhile.
When serverless wins
Azure Functions is the stronger choice when:
- The workload is event-driven — triggered by HTTP requests, queue messages, blob uploads, timers, or Event Grid events.
- Traffic is spiky or unpredictable — the workload sees burst traffic and then goes quiet. Scale-to-zero means zero cost during quiet periods.
- Execution duration is under 10 minutes per invocation.
- The team wants zero infrastructure management — no patching, no scaling configuration, no OS monitoring.
- The workload uses a supported runtime (.NET, Node.js, Python, Java, PowerShell, Go via custom handler).
When VMs win
Azure Virtual Machines are the stronger choice when:
- The workload requires a specific OS, kernel module, custom binary, or runtime not supported by Functions.
- Execution is long-running — processes that run for hours or need persistent in-memory state between executions.
- The workload needs direct network access within a VNet without additional plan costs.
- Latency is extremely sensitive — a VM that is always warm has zero cold start. Premium Functions eliminate cold starts but add cost.
- The workload runs at sustained high throughput where per-execution billing exceeds a fixed VM rate.
- Lift-and-shift — existing applications that are not re-architecturable without significant effort.
Decision checklist
Answer these questions to guide the serverless vs VM decision:
- Is the workload event-driven or continuously running? (Event-driven → Functions; Continuously running → VM)
- Does traffic have significant off-peak periods where scale-to-zero saves money? (Yes → Functions)
- Is each individual execution under 10 minutes? (Yes → Functions viable; No → VM or Durable Functions)
- Does the application require a specific OS, custom runtime, or kernel access? (Yes → VM)
- Does the workload need VNet integration? (Yes, and budget is tight → VM; Yes, and cold starts are a problem → Premium Functions)
- Is the team willing and able to manage OS patching and scaling configuration? (No → Functions wins on operational simplicity)
Common mistakes
- Using VMs for simple event-driven jobs because they are familiar. A background job that processes a queue message every minute is a perfect fit for Functions. Running it on a VM pays for 24/7 compute to do 1 minute of work per hour.
- Using Consumption Functions for latency-sensitive APIs without addressing cold starts. A public-facing API on Consumption plan will show occasional slow responses due to cold starts. Use Premium plan or enable “always ready instances” if response time consistency is critical.
- Assuming serverless always costs less. High-throughput, continuously active workloads can cost more on Functions Consumption than on a modest VM. Model the cost before choosing based on the assumption that serverless is cheaper.
- Forgetting that execution duration limits apply. Long-running data processing jobs that exceed the 10-minute Function timeout will fail mid-execution. Design these for VMs, Batch, or Durable Functions with continuation patterns.
Summary
- Azure Functions (Consumption) charges per execution and scales to zero — ideal for event-driven, spiky workloads. VMs charge per hour and run continuously — better for persistent, long-running processes.
- Cold starts on Consumption plan add 200ms–2s latency; Premium plan eliminates cold starts but adds a base hourly charge.
- VMs win for custom OS requirements, long-running processes, sustained high-throughput workloads, and workloads that need VNet access without additional plan costs.
- Model the cost for your specific execution frequency and duration before assuming serverless is cheaper — at sustained scale it may not be.
Frequently asked questions
Do serverless functions in Azure ever cost more than a VM?
Yes. At high, sustained invocation rates, Azure Functions on Consumption plan can exceed the cost of an equivalent VM. The crossover point depends on execution duration and frequency. Functions are cheapest for spiky or low-frequency workloads; VMs become competitive at sustained high throughput.
What is a cold start and how does it affect Azure Functions?
A cold start is the latency added when a Functions instance that has been idle is initialised to handle a new request. On Consumption plan, cold starts typically add 200ms–2s depending on the runtime and package size. Premium plan and Dedicated plan eliminate cold starts by keeping instances pre-warmed.
Can Azure Functions connect to a private virtual network?
Yes, but not on the Consumption plan by default. VNet integration requires Premium plan or Dedicated (App Service) plan. With VNet integration enabled, functions can access private resources such as Azure SQL, Redis Cache, and internal services within a virtual network.