Start with two questions
- What is the workload? Web app, API, background worker, event handler, batch, legacy server software, or a platform for many teams?
- Who runs it? A product team with no platform engineers needs a different answer from a central platform team running 200 services.
The most common design mistake is choosing the most powerful option instead of the simplest one that fits.
Decision path
Needs full OS control, unsupported runtime, licensed server software, GUI apps?
└─ yes → Virtual Machines (scale sets for identical, stateless instances)
Event-driven, short-running code (queue, timer, blob, HTTP webhook)?
└─ yes → Functions (Container Apps jobs for container-based batch)
Web app or API in a supported language stack, no containers needed?
└─ yes → App Service
Containerised services, want scale-to-zero, Dapr/KEDA, no cluster to manage?
└─ yes → Container Apps
Many services, need Kubernetes APIs, operators, service mesh, fine-grained control, a platform team?
└─ yes → AKS
Comparison
| VMs | App Service | Functions | Container Apps | AKS | |
|---|---|---|---|---|---|
| You manage | OS, patching, runtime, scaling | App code and config | Code | Containers and app config | Cluster, nodes, add-ons, upgrades, workloads |
| Scale | Scale sets / manual | Plan instances, autoscale | Per event, to zero (plan-dependent) | Per HTTP/event, to zero | HPA/KEDA + cluster autoscaler |
| Deployment unit | VM image / config mgmt | Code or container | Code or container | Container | Container + manifests/Helm |
| Network isolation | Full | VNet integration, private endpoints | Plan-dependent | Workload profiles in your VNet | Full |
| Team skills | Windows/Linux admin | Web developers | Developers | Containers | Kubernetes, strong |
| Typical trap | Patching debt, snowflakes | Plan sprawl | Cold starts, timeouts | Feature gaps for edge cases | Running it is a job in itself |
Patterns that work
| Workload | Good fit |
|---|---|
| .NET/Java/Node web app moving off IIS or Tomcat | App Service |
| Handful of microservices, small team | Container Apps |
| 50+ services, shared platform, multiple teams | AKS with a platform team |
| Nightly file processing | Functions or Container Apps jobs |
| COTS application requiring Windows Server | VMs (with Update Manager and backup) |
| SQL Server needing OS-level features | SQL on VM (otherwise a PaaS database) |
Questions to ask in a design review
- Who patches what, and how often? Is that written down?
- How does it scale, and what stops it scaling (database, licences)?
- What are the network requirements (private only, outbound control)?
- How is it deployed, and how is it rolled back?
- What does a zone failure do to it?
- Can the team that owns it operate it at 3 AM?
Mixing is normal
A typical estate uses several: App Service for web front ends, Functions for integrations, AKS or Container Apps for containerised services, VMs for vendor software. Standardise on how things are deployed, monitored and secured, rather than forcing one compute service for everything.
Tip
Revisit the choice when the workload changes shape. An app that grew from 2 to 40 services may outgrow App Service; a cluster now running three services may not justify AKS any more.
Checklist
- Workload shape and operating team identified
- Decision path walked and recorded
- Patching, scaling, network and deployment ownership written down
- Zone failure behaviour understood
- Decision reviewed when the workload changes