Azure Functions on Container Apps — the native kind=functionapp model, the legacy Microsoft.Web model, scaling, identity and limits
Hosting a containerized function app in a Container Apps environment — the recommended V2 model (a Microsoft.App container app with kind functionapp) versus the legacy V1 Microsoft.Web proxy, Bicep with identity-based AzureWebJobsStorage and ACR pull, which triggers scale from zero (Durable only with MSSQL or the Durable Task Scheduler), ingress and storage requirements, multi-revision cautions, and what isn't supported (slots, proxies, portal keys).
markdownreferencev1JR0F-RJ74stage: designtrust: officialservice: functionsinterface: iacinterface: cliAzure Functions on Azure Container Appskind functionappcontainerapp create kind functionappFunctions on Container Apps V1 legacyFunctions on Container Apps V2Microsoft.App/containerApps functionappmigrate Functions on Container AppsallowScalingRuleOverrideKEDA scale rules FunctionsAdd scale rules disabledAzureWebJobsStorage Container Appsdeployment slots not available Container AppsFunctions proxies not supportedFunctions access keys portal Container AppsWEBSITES_PORTappservice-kube extension conflictFunctionsScalerError
Azure Functions on Container Apps
Two models; use the native one
| V2, native (recommended) | V1, legacy | |
|---|---|---|
| Resource | One Microsoft.App/containerApps with kind: functionapp | A Microsoft.Web/sites function app proxying a hidden container app |
| Create | az containerapp create with --kind functionapp (a flag from the containerapp CLI extension; core CLI 2.91 lacks it), or Bicep below | az functionapp create --environment <env> --image … |
| Container Apps features (revisions, secrets, probes, custom domains, sidecars) | Yes | No |
| Future features (function listing, keys, invocation counts) | Planned | Not planned |
A plain container app running a Functions image without kind: functionapp is unsupported: no automatic scale rules. Migrating V1 to V2 needs no code change; redeploy the same image as a V2 app. Both models need a Linux container image you build and push (func init --docker writes the Dockerfile); code changes mean a new image.
Bicep
// Azure Functions on Container Apps (V2, native): a container app with kind 'functionapp'
param location string = resourceGroup().location
param environmentId string
param image string
param identityId string
param storageAccountName string
param identityClientId string
resource fn 'Microsoft.App/containerApps@2026-07-01' = {
name: 'func-orders'
location: location
kind: 'functionapp'
identity: {
type: 'UserAssigned'
userAssignedIdentities: { '${identityId}': {} }
}
properties: {
environmentId: environmentId
configuration: {
ingress: { external: true, targetPort: 80 }
registries: [ { server: split(image, '/')[0], identity: identityId } ]
}
template: {
containers: [
{
name: 'func'
image: image
env: [
{ name: 'AzureWebJobsStorage__accountName', value: storageAccountName }
{ name: 'AzureWebJobsStorage__credential', value: 'managedidentity' }
{ name: 'AzureWebJobsStorage__clientId', value: identityClientId }
]
}
]
scale: { minReplicas: 0, maxReplicas: 10 }
}
}
}
The identity needs AcrPull on the registry and the storage roles for the Functions host (reference/functions/hosting-and-host-storage.md). Microsoft's own walkthrough passes a storage connection string; identity-based AzureWebJobsStorage__* settings avoid the key.
Scaling
The platform writes the KEDA rules from your triggers, so the portal's Add scale rules is disabled; opt out with allowScalingRuleOverride to write your own. Scale events log as FunctionsScalerInfo / FunctionsScalerError in Log Analytics. Up to 1,000 replicas (default maximum 10), scale to zero.
- Ingress must be enabled (external or internal) for event-driven scaling.
- Blob triggers scale only with the Event Grid source. Durable Functions scale only with the MSSQL or Durable Task Scheduler backend (
reference/functions/durable-functions.md). Azure Cache for Redis and Azure SQL triggers don't autoscale: set fixed replicas.
Requirements and gaps
- A storage account is mandatory. With several active revisions, give each revision its own storage account and, for pull triggers (Queue, Event Hubs, Service Bus, Durable), its own event source, or revisions compete for messages.
- No deployment slots (use revisions and traffic splitting), no Functions proxies (use API Management), and no portal-generated function keys: use Easy Auth, internal ingress, a VNet, or API Management.
- Scale-from-zero means cold starts. Environment CPU, memory and replica quotas apply (
reference/container-apps/apps-ingress-and-scale.md). - Legacy model only: the app listens on port 80 unless
WEBSITES_PORTsays otherwise; it can't move between resource groups or subscriptions; and the CLIcontainerappextension conflicts withappservice-kube(remove it).