Azure Container Apps vs. AKS vs. Azure Functions: A Decision Tree for 2026
A practical decision tree comparing Azure Container Apps, AKS, and Azure Functions across operational complexity, scaling, cost, networking, and compliance for enterprise workloads.
Azure offers at least six ways to run application code: Virtual Machines, App Service, Azure Functions, Container Instances, Container Apps, and Azure Kubernetes Service. This abundance of choice paralyses teams who spend weeks debating compute platforms instead of building features.
This guide narrows the decision to the three most relevant options for modern enterprise workloads in 2026: Azure Container Apps (ACA), Azure Kubernetes Service (AKS), and Azure Functions. We provide a clear decision tree, honest trade-offs, and specific guidance on when to use each — and when to combine them.
The Decision Tree
Answer these questions in order. The first "yes" determines your starting point.
This is deliberately simple. The rest of this article provides the nuance behind each decision point.
Comparison Matrix
| Dimension | Azure Container Apps | AKS | Azure Functions |
|---|---|---|---|
| Abstraction level | Managed containers | Managed Kubernetes | Serverless functions |
| Operational complexity | Low | High | Very low |
| Scaling model | KEDA-based, scale-to-zero | HPA/VPA/KEDA, node autoscaler | Event-driven, scale-to-zero |
| Cold start | 5-15 seconds | None (always running) | 1-10 seconds (Consumption), none (Premium) |
| Max execution time | Unlimited (dedicated) | Unlimited | 10 min (Consumption), unlimited (Premium) |
| Networking | VNet injection, managed ingress | Full VNet, any CNI, network policies | VNet integration (Premium only) |
| Dapr integration | Built-in, first-class | Manual installation | Not available |
| KEDA integration | Built-in | Manual installation | Built-in (limited triggers) |
| GPU support | No | Yes | No |
| Custom domains / TLS | Built-in, managed certificates | Manual or cert-manager | Built-in (Premium) |
| Min cost (idle) | EUR 0 (scale-to-zero) | EUR 150+/month (min nodes) | EUR 0 (Consumption plan) |
| Compliance controls | Managed environment | Full infrastructure control | Platform-managed |
| Container runtime | containerd (managed) | containerd (configurable) | N/A (code-based) |
Azure Container Apps: The New Default
Container Apps has matured significantly since its 2022 launch. For most containerised workloads that do not need the full Kubernetes API, it is now the default recommendation.
What Container Apps does well
Automatic scaling with KEDA. Container Apps uses KEDA (Kubernetes Event-Driven Autoscaling) under the hood, supporting 60+ scalers: HTTP requests, Azure Service Bus queue depth, Cosmos DB change feed, Kafka topics, cron schedules, and more.
# Container Apps scaling configuration
properties:
template:
scale:
minReplicas: 0
maxReplicas: 30
rules:
- name: http-scaling
http:
metadata:
concurrentRequests: '50'
- name: queue-scaling
azureQueue:
queueName: orders
queueLength: 10
auth:
- secretRef: queue-connection
triggerParameter: connectionBuilt-in Dapr integration. Dapr (Distributed Application Runtime) provides service invocation, state management, pub/sub messaging, and secret management through a sidecar pattern. On AKS, you install and manage Dapr yourself. On Container Apps, it is a checkbox.
# Dapr configuration in Container Apps
properties:
configuration:
dapr:
enabled: true
appId: order-service
appProtocol: http
appPort: 8080
enableApiLogging: trueManaged ingress with traffic splitting. Blue/green and canary deployments are built-in via revision management and traffic splitting — no need for Istio or Nginx ingress controllers.
# Traffic splitting between revisions
az containerapp ingress traffic set \
--name order-api \
--resource-group rg-production \
--revision-weight latest=20 order-api--v1=80What Container Apps does not do well
- No Kubernetes API access. You cannot use kubectl, Helm charts, or Kubernetes operators. If your CI/CD pipeline or tooling depends on the Kubernetes API, Container Apps requires rethinking.
- No GPU workloads. ML inference, video transcoding, or any GPU-dependent workload requires AKS or VMs.
- Limited networking. No Kubernetes network policies, no custom CNI plugins. You get VNet injection and managed ingress, but not the networking flexibility of AKS.
- No DaemonSets or privileged containers. System-level workloads like log collectors, security agents, or node-level monitoring agents cannot run on Container Apps.
Cost profile
Container Apps pricing is based on vCPU and memory consumption per second, plus HTTP requests for ingress. Scale-to-zero means idle workloads cost nothing.
Example: API serving 100,000 requests/day
- Average 2 replicas, 0.5 vCPU / 1 GB each
- Active 16 hours/day, scaled to zero overnight
- Monthly cost: ~EUR 45 (vCPU/memory) + EUR 5 (requests) = EUR 50The same workload on AKS would cost EUR 150-200/month minimum for the node pool, plus the EUR 0.10/hour cluster management fee.
AKS: When You Need the Full Kubernetes
AKS remains the right choice when your workload genuinely needs Kubernetes features that Container Apps cannot provide.
When AKS is justified
Custom operators and CRDs. If you use operators like Strimzi (Kafka), Prometheus Operator, Cert-Manager, or custom CRDs, you need the Kubernetes API.
Service meshes. Istio, Linkerd, or Consul for advanced traffic management, mTLS, and observability. Container Apps provides basic traffic splitting but not the full service mesh feature set.
GPU workloads. ML model inference, batch processing with GPUs, or any CUDA-dependent workload.
Multi-cluster federation. Active-active deployments across regions with consistent service discovery and configuration.
Compliance requirements. Some compliance frameworks require infrastructure-level control that Container Apps' managed environment cannot provide. If you need to specify exact node OS images, kernel parameters, or run CIS benchmarks against nodes, AKS is necessary.
The hidden cost of AKS
The AKS management fee is EUR 0.10/hour (EUR 73/month). This is the visible cost. The hidden costs are:
AKS cluster management fee: EUR 73/month
Node pool (3x D4s_v5, min): EUR 450/month
Load balancer: EUR 18/month
Managed disks (OS + data): EUR 60/month
Log Analytics workspace: EUR 100/month (typical)
Container Insights: EUR 50/month (typical)
Platform engineer (0.5 FTE): EUR 4,500/month
Training and certifications: EUR 200/month (amortised)
Security tooling (Defender): EUR 75/month
------------------------------------------------------
Total: EUR 5,526/monthThat EUR 73/month cluster fee becomes EUR 5,500/month when you account for everything needed to run AKS in production. This is why Container Apps at EUR 50-200/month is often the right answer.
AKS configuration for production
resource aksCluster 'Microsoft.ContainerService/managedClusters@2024-01-01' = {
name: 'aks-production'
location: 'westeurope'
identity: { type: 'SystemAssigned' }
properties: {
kubernetesVersion: '1.29'
dnsPrefix: 'aks-prod'
networkProfile: {
networkPlugin: 'azure'
networkPolicy: 'calico'
serviceCidr: '10.0.0.0/16'
dnsServiceIP: '10.0.0.10'
loadBalancerSku: 'Standard'
}
agentPoolProfiles: [
{
name: 'system'
count: 3
vmSize: 'Standard_D4s_v5'
availabilityZones: ['1', '2', '3']
mode: 'System'
osSKU: 'AzureLinux'
enableAutoScaling: true
minCount: 3
maxCount: 5
}
{
name: 'workload'
count: 3
vmSize: 'Standard_D8s_v5'
availabilityZones: ['1', '2', '3']
mode: 'User'
osSKU: 'AzureLinux'
enableAutoScaling: true
minCount: 2
maxCount: 20
}
]
addonProfiles: {
azureKeyvaultSecretsProvider: { enabled: true }
omsagent: {
enabled: true
config: { logAnalyticsWorkspaceResourceID: logAnalyticsId }
}
}
autoUpgradeProfile: { upgradeChannel: 'stable' }
securityProfile: {
defender: { securityMonitoring: { enabled: true } }
workloadIdentity: { enabled: true }
}
oidcIssuerProfile: { enabled: true }
}
}Azure Functions: Event-Driven Glue
Azure Functions is not a general-purpose compute platform. It is optimised for event-driven, short-lived executions. Using it as a general-purpose API backend leads to pain.
When Functions is the right choice
- Event processing: Service Bus message handlers, Event Grid subscribers, Cosmos DB change feed processors
- Scheduled tasks: Cron-based cleanup jobs, report generation, data synchronisation
- Lightweight APIs: Simple REST endpoints with low traffic that benefit from scale-to-zero
- Integration glue: Connecting SaaS services, transforming data between systems, webhook handlers
When Functions is the wrong choice
- Long-running processes: Anything exceeding 10 minutes on Consumption plan (use Durable Functions or Container Apps)
- Stateful workloads: Functions are stateless by design (Durable Functions add state but with complexity)
- High-throughput APIs: Cold starts on Consumption plan create latency spikes. Premium plan eliminates cold starts but at EUR 150+/month minimum
- Complex microservices: If you need sidecar patterns, service discovery, or inter-service communication, use Container Apps
Functions hosting plans comparison
| Plan | Cold Start | Min Cost | Max Instances | Timeout | VNet |
|---|---|---|---|---|---|
| Consumption | 1-10 sec | EUR 0 | 200 | 10 min | No |
| Flex Consumption | 0-1 sec | EUR 0 | 1000 | Unlimited | Yes |
| Premium (EP1) | None | EUR 150/month | 100 | Unlimited | Yes |
| Dedicated (App Service) | None | EUR 50+/month | 30 | Unlimited | Yes |
Functions with KEDA triggers
// Azure Function with Service Bus trigger
[Function("ProcessOrder")]
public async Task Run(
[ServiceBusTrigger("orders", Connection = "ServiceBusConnection")]
ServiceBusReceivedMessage message,
ServiceBusMessageActions messageActions,
FunctionContext context)
{
var logger = context.GetLogger("ProcessOrder");
var order = JsonSerializer.Deserialize<Order>(message.Body);
try
{
await _orderService.ProcessAsync(order);
await messageActions.CompleteMessageAsync(message);
logger.LogInformation("Order {OrderId} processed", order.Id);
}
catch (Exception ex)
{
logger.LogError(ex, "Failed to process order {OrderId}", order.Id);
// Message will be retried based on Service Bus retry policy
throw;
}
}When to Combine Services
The best architectures often use multiple compute services. Here is a proven pattern:
Container Apps handles the stateless API layer with automatic scaling and managed ingress.
Azure Functions processes asynchronous events from Service Bus, Event Grid, and Cosmos DB change feeds.
AKS runs workloads that need GPUs, custom operators, or the full Kubernetes API.
This is not over-engineering — it is using each service for what it does best. The key is clear boundaries: synchronous APIs go to Container Apps, asynchronous events go to Functions, and anything needing Kubernetes goes to AKS.
Complexity vs. Control Trade-Off
Migration Paths
From AKS to Container Apps
If you are running simple workloads on AKS that do not use Kubernetes-specific features, Container Apps can reduce operational burden and cost.
- Inventory all Kubernetes features used (CRDs, operators, network policies, node access)
- Identify workloads that only use basic Deployments, Services, and ConfigMaps
- Convert Kubernetes manifests to Container Apps configuration (Dapr annotations map directly)
- Migrate one workload at a time, starting with the simplest
From App Service to Container Apps
Container Apps is the natural evolution from App Service for containerised workloads that need finer scaling control.
- Containerise the application if not already
- Configure KEDA scaling rules (HTTP scaler replaces App Service auto-scale)
- Migrate custom domains and managed certificates
- Verify VNet integration works with private endpoints
Cost Optimisation Decision Framework
| Monthly Budget | Team Size | Workload Type | Recommendation |
|---|---|---|---|
| < EUR 200 | No platform team | APIs, microservices | Container Apps |
| < EUR 200 | No platform team | Event processing | Azure Functions |
| EUR 200-2,000 | 1-2 engineers | Mixed workloads | Container Apps + Functions |
| EUR 2,000-10,000 | 3-5 engineers | Complex, multi-service | Evaluate AKS vs Container Apps |
| > EUR 10,000 | Dedicated platform team | Enterprise platform | AKS + Container Apps + Functions |
Next Steps
The compute platform decision should take hours, not weeks. Use the decision tree above, evaluate honestly whether your workloads need Kubernetes features, and default to the simplest option that meets your requirements.
If you are running AKS and questioning whether the complexity is justified, or evaluating Container Apps for a new project, reach out at mbrahim@conceptualise.de. We help enterprises right-size their compute platform decisions — which often means simplifying from AKS to Container Apps and saving significant operational cost.
Topics