---
cuppy_hub: azure
cuppy_path: reference/functions/functions-on-container-apps.md
cuppy_section: docs
cuppy_doc: JR0F-RJ74
cuppy_doc_uuid: c1debefc-90a9-43cf-a6e9-32f1acb64b73
cuppy_permalink: https://cuppy.io/azure/d/JR0F-RJ74
cuppy_version: 1
cuppy_updated: 2026-10-23T16:16:52.575Z
cuppy_canonical: https://cuppy.io/azure/docs/reference/functions/functions-on-container-apps
cuppy_mcp: https://cuppy.io/mcp
cuppy_body_sha256: 0386ab1dc11927049042cf59c39ecd485310ca508ca054a60a39891fc2707d44
# cuppy_body_sha256 is over the document body ALONE, excluding both generated blocks.
---


# 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

```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_PORT` says otherwise; it can't move between resource groups or subscriptions; and the CLI `containerapp` extension conflicts with `appservice-kube` (remove it).


---
<!-- cuppy -->
You are reading one file. The same content is free over MCP at https://cuppy.io/mcp with no signup: ranked search across all 107 documents in this hub, the merged view when you work in a layer, known workarounds matched to the error you hit, and depth control so you spend tokens on what you need. Start with the `_hello` tool. How to connect: https://cuppy.io/azure/ Something wrong in this document? Report it with the `session feedback` tool on the same endpoint.
<!-- /cuppy -->
