Automate resource deployment for your function app in Azure Functions

You can use a Bicep file or an Azure Resource Manager template to automate the process of deploying a function app to new or existing Azure resources. Such automation provides a great way to be able to integrate your resource deployments with your source code in DevOps, restore a function app and related resources from a backup, or deploy an app topology multiple times.

This article shows you how to automate the creation of resources and deployment for Azure Functions. Depending on the triggers and bindings used by your functions, you might need to deploy other resources, which is outside of the scope of this article.

The specific template code depends on how your function app is hosted, whether you're deploying code or a containerized function app, and the operating system used by your app. This article supports the following hosting options:

Hosting option Deployment type To learn more, see...
Azure Functions Consumption plan Code-only Consumption plan
Azure Functions Elastic Premium plan Code | Container Premium plan
Azure Functions Dedicated (App Service) plan Code | Container Dedicated plan
Azure Container Apps Container-only Container Apps hosting of Azure Functions
Azure Arc Code | Container App Service, Functions, and Logic Apps on Azure Arc (Preview)

Required resources

An Azure Functions-hosted deployment typically consists of these resources:

Resource Requirement Syntax and properties reference
A storage account Required Microsoft.Storage/storageAccounts
An Application Insights component Recommended Microsoft.Insights/components
A hosting plan Required1 Microsoft.Web/serverfarms
A function app Required Microsoft.Web/sites

An Azure Functions deployment for a Consumption plan typically consists of these resources:

Resource Requirement Syntax and properties reference
A storage account Required Microsoft.Storage/storageAccounts
An Application Insights component Recommended Microsoft.Insights/components
A function app Required Microsoft.Web/sites

An Azure Container Apps-hosted deployment typically consists of these resources:

Resource Requirement Syntax and properties reference
A storage account Required Microsoft.Storage/storageAccounts
An Application Insights component Recommended Microsoft.Insights/components
A managed environment Required Microsoft.App/managedEnvironments
A function app Required Microsoft.Web/sites

An Azure Arc-hosted deployment typically consists of these resources:

Resource Requirement Syntax and properties reference
A storage account Required Microsoft.Storage/storageAccounts
An Application Insights component Recommended Microsoft.Insights/components
An App Service Kubernetes environment Required Microsoft.ExtendedLocation/customLocations
A function app Required Microsoft.Web/sites

1An explicit hosting plan isn't required when you choose to host your function app in a Consumption plan.

When you deploy multiple resources in a single Bicep file or ARM template, the order in which resources are created is important. This requirement is a result of dependencies between resources. For such dependencies, make sure to use the dependsOn element to define the dependency in the dependent resource. For more information, see either Define the order for deploying resources in ARM templates or Resource dependencies in Bicep.

This article assumes that you have a basic understanding about creating Bicep files or authoring Azure Resource Manager templates, and examples are shown as individual sections for specific resources. For a broad set of complete Bicep file and ARM template examples, see these function app deployment examples.

Prerequisites

This article assumes that you have already created a managed environment in Azure Container Apps. You need both the name and the ID of the managed environment to create a function app hosted on Container Apps.

This article assumes that you have already created an App Service-enabled custom location on an Azure Arc-enabled Kubernetes cluster. You need both the custom location ID and the Kubernetes environment ID to create a function app hosted in an Azure Arc custom location.

Create storage account

All function apps require an Azure storage account. You need a general purpose account that supports blobs, tables, queues, and files. For more information, see Azure Functions storage account requirements.

Important

The storage account is used to store important app data, sometimes including the application code itself. You should limit access from other apps and users to the storage account.

This example section creates a Standard general-purpose v2 storage account:

"resources": [
  {
    "type": "Microsoft.Storage/storageAccounts",
    "apiVersion": "2022-05-01",
    "name": "[parameters('storageAccountName')]",
    "location": "[parameters('location')]",
    "kind": "StorageV2",
    "sku": {
      "name": "[parameters('storageAccountType')]"
    },
    "properties": {
      "supportsHttpsTrafficOnly": true,
      "defaultToOAuthAuthentication": true
    }
  }
]

For more context, see the complete azuredeploy.json file in the templates repository.

You need to set the connection string of this storage account as the AzureWebJobsStorage app setting, which Functions requires. The templates in this article construct this connection string value based on the created storage account, which is a best practice. For more information, see Application configuration.

Enable storage logs

Because the storage account is used for important function app data, you should monitor the account for modification of that content. To monitor your storage account, you need to configure Azure Monitor resource logs for Azure Storage. In this example section, a Log Analytics workspace named myLogAnalytics is used as the destination for these logs.

"resources": [
  {
    "type": "Microsoft.Insights/diagnosticSettings",
    "apiVersion": "2021-05-01-preview",
    "scope": "[format('Microsoft.Storage/storageAccounts/{0}/blobServices/default', parameters('storageAccountName'))]",
    "name": "[parameters('storageDataPlaneLogsName')]",
    "properties": {
        "workspaceId": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('myLogAnalytics'))]",
        "logs": [
          {
            "category": "StorageWrite",
            "enabled": true
          }
        ],
        "metrics": [
          {
            "category": "Transaction",
            "enabled": true
          }
        ]
    }
  }
]

This same workspace can be used for the Application Insights resource defined later. For more information, including how to work with these logs, see Monitoring Azure Storage.

Create Application Insights

Application Insights is recommended for monitoring your function app executions. In this example section, the Application Insights resource is defined with the type Microsoft.Insights/components and the kind web:

{
  "type": "Microsoft.Insights/components",
  "apiVersion": "2020-02-02",
  "name": "[variables('applicationInsightsName')]",
  "location": "[parameters('appInsightsLocation')]",
  "tags": {
    "[format('hidden-link:{0}', resourceId('Microsoft.Web/sites', parameters('functionAppName')))]": "Resource"
  },
  "properties": {
    "Application_Type": "web"
  },
  "kind": "web"
},

For more context, see the complete azuredeploy.json file in the templates repository.

The connection must be provided to the function app using the APPLICATIONINSIGHTS_CONNECTION_STRING application setting. For more information, see Application settings.

The examples in this article obtain the connection string value for the created instance. Older versions might instead use APPINSIGHTS_INSTRUMENTATIONKEY to set the instrumentation key, which is no longer recommended.

Create the hosting plan

Apps hosted in an Azure Functions Premium plan or Dedicated (App Service) plan must have the hosting plan explicitly defined.

The Premium plan offers the same scaling as the Consumption plan but includes dedicated resources and extra capabilities. To learn more, see Azure Functions Premium Plan.

A Premium plan is a special type of serverfarm resource. You can specify it by using either EP1, EP2, or EP3 for the Name property value in the sku property. The way that you define the Functions hosting plan depends on whether your function app runs on Windows or on Linux. This example section creates an EP1 plan:

"resources": [
  {
    "type": "Microsoft.Web/serverfarms",
    "apiVersion": "2022-03-01",
    "name": "[parameters('hostingPlanName')]",
    "location": "[parameters('location')]",
    "sku": {
      "name": "EP1",
      "tier": "ElasticPremium",
      "family": "EP"
    },
    "kind": "elastic",
    "properties": {
      "maximumElasticWorkerCount": 20
    }
  }
]

For more context, see the complete azuredeploy.json file in the templates repository.

For more information about the sku object, see SkuDefinition or review the example templates.

In the Dedicated (App Service) plan, your function app runs on dedicated VMs on Basic, Standard, and Premium SKUs in App Service plans, similar to web apps. For more information, see Dedicated plan.

For a sample Bicep file/Azure Resource Manager template, see Function app on Azure App Service plan

In Functions, the Dedicated plan is just a regular App Service plan, which is defined by a serverfarm resource. You must provide at least the name value. For a list of supported plan names, see the --sku setting in az appservice plan create for the current list of supported values for a Dedicated plan.

The way that you define the hosting plan depends on whether your function app runs on Windows or on Linux:

"resources": [
  {
    "type": "Microsoft.Web/serverfarms",
    "apiVersion": "2022-03-01",
    "name": "[parameters('hostingPlanName')]",
    "location": "[parameters('location')]",
    "sku": {
      "tier": "Standard",
      "name": "S1",
      "size": "S1",
      "family": "S",
      "capacity": 1
    }
  }
]

For more context, see the complete azuredeploy.json file in the templates repository.

Create the hosting plan

You don't need to explicitly define a Consumption hosting plan resource. When you skip this resource definition, a plan is automatically either created or selected on a per-region basis when you create the function app resource itself.

You can explicitly define a Consumption plan as a special type of serverfarm resource, which you specify using the value Dynamic for the computeMode and sku properties. This example section shows you how to explicitly define a consumption plan. The way that you define a hosting plan depends on whether your function app runs on Windows or on Linux.

"resources": [
  {
    "type": "Microsoft.Web/serverfarms",
    "apiVersion": "2022-03-01",
    "name": "[parameters('hostingPlanName')]",
    "location": "[parameters('location')]",
    "sku": {
      "name": "Y1",
      "tier": "Dynamic",
      "size": "Y1",
      "family": "Y",
      "capacity": 0
    },
    "properties": {
      "computeMode": "Dynamic"
    }
  }
]

For more context, see the complete azuredeploy.json file in the templates repository.

Kubernetes environment

Azure Functions can be deployed to Azure Arc-enabled Kubernetes either as a code project or a containerized function app.

To create the app and plan resources, you must have already created an App Service Kubernetes environment for an Azure Arc-enabled Kubernetes cluster. The examples in this article assume you have the resource ID of the custom location (customLocationId) and App Service Kubernetes environment (kubeEnvironmentId) to which you're deploying, which are set in this example:

"parameters": {
  "kubeEnvironmentId" : {
    "type": "string"
  },
  "customLocationId" : {
    "type": "string"
  }
}

Both sites and plans must reference the custom location through an extendedLocation field. As shown in this truncated example, extendedLocation sits outside of properties, as a peer to kind and location:

{
  "type": "Microsoft.Web/serverfarms",
  ...
  {
    "extendedLocation": {
      "name": "[parameters('customLocationId')]"
    },
  }
}

The plan resource should use the Kubernetes (K1) value for SKU, the kind field should be linux,kubernetes, and the reserved property should be true, since it's a Linux deployment. You must also set the extendedLocation and kubeEnvironmentProfile.id to the custom location ID and the Kubernetes environment ID, respectively, which might look like this example section:

"resources": [
  {
    "type": "Microsoft.Web/serverfarms",
    "apiVersion": "2022-03-01",
    "name": "[parameters('hostingPlanName')]",
    "location": "[parameters('location')]",
    "kind": "linux,kubernetes",
    "sku": {
      "name": "K1",
      "tier": "Kubernetes"
    },
    "extendedLocation": {
      "name": "[parameters('customLocationId')]"
    },
    "properties": {
      "kubeEnvironmentProfile": {
        "id": "[parameters('kubeEnvironmentId')]"
      },
      "reserved": true
    }
  }
]

Create the function app

The function app resource is defined by a resource of type Microsoft.Web/sites and kind that includes functionapp, at a minimum.

The way that you define a function app resource depends on whether you're hosting on Linux or on Windows:

For a list of application settings required when running on Windows, see Application configuration. For a sample Bicep file/Azure Resource Manager template, see the function app hosted on Windows in a Consumption plan template.

For a list of application settings required when running on Windows, see Application configuration.

Note

If you choose to optionally define your Consumption plan, you must set the serverFarmId property on the app so that it points to the resource ID of the plan. Make sure that the function app has a dependsOn setting that also references the plan. If you didn't explicitly define a plan, one gets created for you.

Set the serverFarmId property on the app so that it points to the resource ID of the plan. Make sure that the function app has a dependsOn setting that also references the plan.

"resources": [
  {
    "type": "Microsoft.Web/sites",
    "apiVersion": "2022-03-01",
    "name": "[parameters('functionAppName')]",
    "location": "[parameters('location')]",
    "kind": "functionapp",
    "dependsOn": [
      "[resourceId('Microsoft.Insights/components', parameters('applicationInsightsName'))]",
      "[resourceId('Microsoft.Web/serverfarms', parameters('hostingPlanName'))]",
      "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]"
    ],
    "properties": {
      "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', parameters('hostingPlanName'))]",
      "siteConfig": {
        "appSettings": [
          {
            "name": "APPLICATIONINSIGHTS_CONNECTION_STRING",
            "value": "[reference(resourceId('Microsoft.Insights/components', parameters('applicationInsightsName')), '2020-02-02').ConnectionString]"
          },
          {
            "name": "AzureWebJobsStorage",
            "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};EndpointSuffix={1};AccountKey={2}', parameters('storageAccountName'), environment().suffixes.storage, listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2021-09-01').keys[0].value)]"
          },
          {
            "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
            "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};EndpointSuffix={1};AccountKey={2}', parameters('storageAccountName'), environment().suffixes.storage, listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2021-09-01').keys[0].value)]"
          },
          {
            "name": "WEBSITE_CONTENTSHARE",
            "value": "[toLower(parameters('functionAppName'))]"
          },
          {
            "name": "FUNCTIONS_EXTENSION_VERSION",
            "value": "~4"
          },
          {
            "name": "FUNCTIONS_WORKER_RUNTIME",
            "value": "node"
          },
          {
            "name": "WEBSITE_NODE_DEFAULT_VERSION",
            "value": "~14"
          }
        ]
      }
    }
  }
]

For a complete end-to-end example, see this azuredeploy.json template.

"resources": [
  {
    "type": "Microsoft.Web/sites",
    "apiVersion": "2022-03-01",
    "name": "[parameters('functionAppName')]",
    "location": "[parameters('location')]",
    "kind": "functionapp",
    "dependsOn": [
      "[resourceId('Microsoft.Insights/components', parameters('applicationInsightsName'))]",
      "[resourceId('Microsoft.Web/serverfarms', parameters('hostingPlanName'))]",
      "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]"
    ],
    "properties": {
      "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', parameters('hostingPlanName'))]",
      "siteConfig": {
        "alwaysOn": true,
        "appSettings": [
          {
            "name": "APPLICATIONINSIGHTS_CONNECTION_STRING",
            "value": "[reference(resourceId('Microsoft.Insights/components', parameters('applicationInsightsName')), '2020-02-02').ConnectionString]"
          },
          {
            "name": "AzureWebJobsStorage",
            "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};EndpointSuffix={1};AccountKey={2}', parameters('storageAccountName'), environment().suffixes.storage, listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2021-09-01').keys[0].value)]"
          },
          {
            "name": "FUNCTIONS_EXTENSION_VERSION",
            "value": "~4"
          },
          {
            "name": "FUNCTIONS_WORKER_RUNTIME",
            "value": "node"
          },
          {
            "name": "WEBSITE_NODE_DEFAULT_VERSION",
            "value": "~14"
          }
        ]
      }
    }
  }
]

For a complete end-to-end example, see this azuredeploy.json template.

Deployment sources

Your Bicep file or ARM template can optionally also define a deployment for your function code, which could include these methods:

Deployment sources

Your Bicep file or ARM template can optionally also define a deployment for your function code using a zip deployment package.

To successfully deploy your application by using Azure Resource Manager, it's important to understand how resources are deployed in Azure. In most examples, top-level configurations are applied by using siteConfig. It's important to set these configurations at a top level, because they convey information to the Functions runtime and deployment engine. Top-level information is required before the child sourcecontrols/web resource is applied. Although it's possible to configure these settings in the child-level config/appSettings resource, in some cases your function app must be deployed before config/appSettings is applied.

Zip deployment package

Zip deployment is a recommended way to deploy your function app code. By default, functions that use zip deployment run in the deployment package itself. For more information, including the requirements for a deployment package, see Zip deployment for Azure Functions. When using resource deployment automation, you can reference the .zip deployment package in your Bicep or ARM template.

To use zip deployment in your template, set the WEBSITE_RUN_FROM_PACKAGE setting in the app to 1 and include the /zipDeploy resource definition.

For a Consumption plan on Linux, instead set the URI of the deployment package directly in the WEBSITE_RUN_FROM_PACKAGE setting, as shown in this example template.

This example adds a zip deployment source to an existing app:

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "functionAppName": {
      "type": "string",
      "metadata": {
        "description": "The name of the Azure Function app."
      }
    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "metadata": {
        "description": "The location into which the resources should be deployed."
      }
    },
    "packageUri": {
      "type": "string",
      "metadata": {
        "description": "The zip content url."
      }
    }
  },
  "resources": [
    {
      "name": "[concat(parameters('functionAppName'), '/ZipDeploy')]",
      "type": "Microsoft.Web/sites/extensions",
      "apiVersion": "2021-02-01",
      "location": "[parameters('location')]",
      "properties": {
        "packageUri": "[parameters('packageUri')]"
      }
    }
  ]
}

Keep the following things in mind when including zip deployment resources in your template:

  • The packageUri must be a location that can be accessed by Functions. Consider using Azure blob storage with a shared access signature (SAS). After the SAS expires, Functions can no longer access the share for deployments. When you regenerate your SAS, remember to update the WEBSITE_RUN_FROM_PACKAGE setting with the new URI value.

  • Make sure to always set all required application settings in the appSettings collection when adding or updating settings. Existing settings not explicitly set are removed by the update. For more information, see Application configuration.

  • Functions doesn't support Web Deploy (msdeploy) for package deployments. You must instead use zip deployment in your deployment pipelines and automation. For more information, see Zip deployment for Azure Functions.

Remote builds

The deployment process assumes that the .zip file that you use or a zip deployment contains a ready-to-run app. This means that by default no customizations are run.

However, there are scenarios that require you to rebuild your app remotely, such as when you need to pull Linux-specific packages in Python or Node.js apps that you developed on a Windows computer. In this case, you can configure Functions to perform a remote build on your code after the zip deployment.

The way that you request a remote build depends on the operating system to which you are deploying:

When an app is deployed to Windows, language-specific commands (like dotnet restore for C# apps or npm install for Node.js apps) are run.

To enable the same build processes that you get with continuous integration, add SCM_DO_BUILD_DURING_DEPLOYMENT=true to your application settings in your deployment code and remove the WEBSITE_RUN_FROM_PACKAGE entirely.

Linux containers

If you're deploying a containerized function app to an Azure Functions Premium or Dedicated plan, you must:

For more information, see Application configuration.

"resources": [
  {
    "type": "Microsoft.Web/sites",
    "apiVersion": "2022-03-01",
    "name": "[parameters('functionAppName')]",
    "location": "[parameters('location')]",
    "kind": "functionapp",
    "dependsOn": [
      "[resourceId('Microsoft.Web/serverfarms', parameters('hostingPlanName'))]",
      "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]"
    ],
    "properties": {
      "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', parameters('hostingPlanName'))]",
      "siteConfig": {
        "appSettings": [
          {
            "name": "AzureWebJobsStorage",
            "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}', parameters('storageAccountName'), listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2021-09-01').keys[0].value)]"
          },
          {
            "name": "FUNCTIONS_WORKER_RUNTIME",
            "value": "node"
          },
          {
            "name": "WEBSITE_NODE_DEFAULT_VERSION",
            "value": "~14"
          },
          {
            "name": "FUNCTIONS_EXTENSION_VERSION",
            "value": "~4"
          },
          {
            "name": "DOCKER_REGISTRY_SERVER_URL",
            "value": "[parameters('dockerRegistryUrl')]"
          },
          {
            "name": "DOCKER_REGISTRY_SERVER_USERNAME",
            "value": "[parameters('dockerRegistryUsername')]"
          },
          {
            "name": "DOCKER_REGISTRY_SERVER_PASSWORD",
            "value": "[parameters('dockerRegistryPassword')]"
          },
          {
            "name": "WEBSITES_ENABLE_APP_SERVICE_STORAGE",
            "value": "false"
          }
        ],
        "linuxFxVersion": "DOCKER|myacr.azurecr.io/myimage:mytag"
      }
    }
  }
]

When deploying containerized functions to Azure Container Apps, your template must:

  • Set the kind field to a value of functionapp,linux,container,azurecontainerapps.
  • Set the managedEnvironmentId site property to the fully qualified URI of the Container Apps environment.
  • Add a resource link in the site's dependsOn collection when creating a Microsoft.App/managedEnvironments resource at the same time as the site.

The definition of a containerized function app deployed from a private container registry to an existing Container Apps environment might look like this example:

"resources": [
  {
    "type": "Microsoft.Web/sites",
    "apiVersion": "2022-03-01",
    "name": "[parameters('functionAppName')]",
    "kind": "functionapp,linux,container,azurecontainerapps",
    "location": "[parameters('location')]",
    "dependsOn": [
      "[resourceId('Microsoft.Insights/components', parameters('applicationInsightsName'))]",
      "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]"
    ],
    "properties": {
      "serverFarmId": "[parameters('hostingPlanName')]",
      "siteConfig": {
        "linuxFxVersion": "DOCKER|myacr.azurecr.io/myimage:mytag",
        "appSettings": [
          {
            "name": "FUNCTIONS_EXTENSION_VERSION",
            "value": "~4"
          },
          {
            "name": "AzureWebJobsStorage",
            "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}', parameters('storageAccountName'), listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2021-09-01').keys[0].value)]"
          },
          {
            "name": "APPLICATIONINSIGHTS_CONNECTION_STRING",
            "value": "[reference(resourceId('Microsoft.Insights/components', parameters('applicationInsightsName')), '2020-02-02').ConnectionString]"
          }
        ],
      },
      "managedEnvironmentId": "[parameters('managedEnvironmentId')]"
    }
  }
]

When deploying functions to Azure Arc, the value you set for the kind field of the function app resource depends on the type of deployment:

Deployment type kind field value
Code-only deployment functionapp,linux,kubernetes
Container deployment functionapp,linux,kubernetes,container

You must also set the customLocationId as you did for the hosting plan resource.

The definition of a containerized function app, using a .NET 6 quickstart image, might look like this example:

"resources": [
  {
    "type": "Microsoft.Web/sites",
    "apiVersion": "2022-03-01",
    "name": "[parameters('functionAppName')]",
    "kind": "kubernetes,functionapp,linux,container",
    "location": "[parameters('location')]",
    "extendedLocation": {
      "name": "[parameters('customLocationId')]"
    },
    "dependsOn": [
      "[resourceId('Microsoft.Insights/components', parameters('applicationInsightsName'))]",
      "[resourceId('Microsoft.Web/serverfarms', parameters('hostingPlanName'))]",
      "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]"
    ],
    "properties": {
      "serverFarmId": "[parameters('hostingPlanName')]",
      "siteConfig": {
        "linuxFxVersion": "DOCKER|mcr.microsoft.com/azure-functions/4-dotnet-isolated6.0-appservice-quickstart",
        "appSettings": [
          {
            "name": "FUNCTIONS_EXTENSION_VERSION",
            "value": "~4"
          },
          {
            "name": "AzureWebJobsStorage",
            "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}', parameters('storageAccountName'), listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2021-09-01').keys[0].value)]"
          },
          {
            "name": "APPLICATIONINSIGHTS_CONNECTION_STRING",
            "value": "[reference(resourceId('Microsoft.Insights/components', parameters('applicationInsightsName')), '2020-02-02').ConnectionString]"
          }
        ],
        "alwaysOn": true
      }
    }
  }
]

Application configuration

Functions provides the following options for configuring your function app in Azure:

Configuration Microsoft.Web/sites property
Site settings siteConfig
Application settings siteConfig.appSettings collection

The following site settings are required on the siteConfig property:

These application settings are required (or recommended) for a specific operating system and hosting option:

These application settings are required for container deployments:

These settings are only required when deploying from a private container registry:

Keep these considerations in mind when working with site and application settings using Bicep files or ARM templates:

  • There are important considerations for when you should set WEBSITE_CONTENTSHARE in an automated deployment. For detailed guidance, see the WEBSITE_CONTENTSHARE reference.
  • You should always define your application settings as a siteConfig/appSettings collection of the Microsoft.Web/sites resource being created, as is done in the examples in this article. This makes sure that the settings that your function app needs to run are available on initial startup.

  • When adding or updating application settings using templates, make sure that you include all existing settings with the update. You must do this because the underlying update REST API calls replace the entire /config/appsettings resource. If you remove the existing settings, your function app won't run. To programmatically update individual application settings, you can instead use the Azure CLI, Azure PowerShell, or the Azure portal to make these changes. For more information, see Work with application settings.

Slot deployments

Functions lets you deploy different versions of your code to unique endpoints in your function app. This makes it easier to develop, validate, and deploy functions updates without impacting functions running in production. Deployment slots is a feature of Azure App Service. The number of slots available depends on your hosting plan. For more information, see Azure Functions deployment slots functions.

A slot resource is defined in the same way as a function app resource (Microsoft.Web/sites), but instead you use the Microsoft.Web/sites/slots resource identifier. For an example deployment (in both Bicep and ARM templates) that creates both a production and a staging slot in a Premium plan, see Azure Function App with a Deployment Slot.

To learn about how to perform the swap by using templates, see Automate with Resource Manager templates.

Keep the following considerations in mind when working with slot deployments:

  • Don't explicitly set the WEBSITE_CONTENTSHARE setting in the deployment slot definition. This setting is generated for you when the app is created in the deployment slot.

  • When you swap slots, some application settings are considered "sticky," in that they stay with the slot and not with the code being swapped. You can define such a slot setting by including "slotSetting":true in the specific application setting definition in your template. For more information, see Manage settings.

Secured deployments

You can create your function app in a deployment where one or more of the resources have been secured by integrating with virtual networks. Virtual network integration for your function app is defined by a Microsoft.Web/sites/networkConfig resource. This integration depends on both the referenced function app and virtual network resources. Your function app might also depend on other private networking resources, such as private endpoints and routes. For more information, see Azure Functions networking options.

When creating a deployment that uses a secured storage account, you must both explicitly set the WEBSITE_CONTENTSHARE setting and create the file share resource named in this setting. Make sure you create a Microsoft.Storage/storageAccounts/fileServices/shares resource using the value of WEBSITE_CONTENTSHARE, as shown in this example (ARM template|Bicep file).

These projects provide both Bicep and ARM template examples of how to deploy your function apps in a virtual network, including with network access restrictions:

Restricted scenario Description
Create a function app with virtual network integration Your function app is created in a virtual network with full access to resources in that network. Inbound and outbound access to your function app isn't restricted. For more information, see Virtual network integration.
Create a function app that accesses a secured storage account Your created function app uses a secured storage account, which Functions accesses by using private endpoints. For more information, see Restrict your storage account to a virtual network.
Create a function app and storage account that both use private endpoints Your created function app can only be accessed by using private endpoints, and it uses private endpoints to access storage resources. For more information, see Private endpoints.

Restricted network settings

You might also need to use these settings when your function app has network restrictions:

Setting Value Description
WEBSITE_CONTENTOVERVNET 1 Application setting that enables your function app to scale when the storage account is restricted to a virtual network. For more information, see Restrict your storage account to a virtual network.
vnetrouteallenabled 1 Site setting that forces all traffic from the function app to use the virtual network. For more information, see Regional virtual network integration. This site setting supersedes the application setting WEBSITE_VNET_ROUTE_ALL.

Considerations for network restrictions

When you're restricting access to the storage account through the private endpoints, you aren't able to access the storage account through the portal or any device outside the virtual network. You can give access to your secured IP address or virtual network in the storage account by Managing the default network access rule.

Create your template

Experts with Bicep or ARM templates can manually code their deployments using a simple text editor. For the rest of us, there are several ways to make the development process easier:

  • Visual Studio Code: There are extensions available to help you work with both Bicep files and ARM templates. You can use these tools to help make sure that your code is correct, and they provide some basic validation.

  • Azure portal: When you create your function app and related resources in the portal, the final Review + create screen has a Download a template for automation link.

    Download template link from the Azure Functions creation process in the Azure portal.

    This link shows you the ARM template generated based on the options you chose in portal. While this template can be a bit complex when you're creating a function app with many new resources, it can provide a good reference for how your ARM template might look.

Validate your template

When you manually create your deployment template file, it's important to validate your template before deployment. All deployment methods validate your template syntax and raise a validation failed error message as shown in the following JSON formatted example:

{"error":{"code":"InvalidTemplate","message":"Deployment template validation failed: 'The resource 'Microsoft.Web/sites/func-xyz' is not defined in the template. Please see https://aka.ms/arm-template for usage details.'.","additionalInfo":[{"type":"TemplateViolation","info":{"lineNumber":0,"linePosition":0,"path":""}}]}}

The following methods can be used to validate your template before deployment:

The following Azure resource group deployment v2 task with deploymentMode: 'Validation' instructs Azure Pipelines to validate the template.

- task: AzureResourceManagerTemplateDeployment@3
  inputs:
    deploymentScope: 'Resource Group'
    subscriptionId: # Required subscription ID
    action: 'Create Or Update Resource Group'
    resourceGroupName: # Required resource group name
    location: # Required when action == Create Or Update Resource Group
    templateLocation: 'Linked artifact'
    csmFile: # Required when  TemplateLocation == Linked Artifact
    csmParametersFile: # Optional
    deploymentMode: 'Validation'

You can also create a test resource group to find preflight and deployment errors.

Deploy your template

You can use any of the following ways to deploy your Bicep file and template:

Deploy to Azure button

Note

This method doesn't support deploying Bicep files currently.

Replace <url-encoded-path-to-azuredeploy-json> with a URL-encoded version of the raw path of your azuredeploy.json file in GitHub.

Here's an example that uses markdown:

[![Deploy to Azure](https://azuredeploy.net/deploybutton.png)](https://portal.azure.com/#create/Microsoft.Template/uri/<url-encoded-path-to-azuredeploy-json>)

Here's an example that uses HTML:

<a href="https://portal.azure.com/#create/Microsoft.Template/uri/<url-encoded-path-to-azuredeploy-json>" target="_blank"><img src="https://azuredeploy.net/deploybutton.png"></a>

Deploy using PowerShell

The following PowerShell commands create a resource group and deploy a Bicep file/ARM template that creates a function app with its required resources. To run locally, you must have Azure PowerShell installed. Run Connect-AzAccount to sign in.

# Register Resource Providers if they're not already registered
Register-AzResourceProvider -ProviderNamespace "microsoft.web"
Register-AzResourceProvider -ProviderNamespace "microsoft.storage"

# Create a resource group for the function app
New-AzResourceGroup -Name "MyResourceGroup" -Location 'West Europe'

# Deploy the template
New-AzResourceGroupDeployment -ResourceGroupName "MyResourceGroup" -TemplateFile azuredeploy.json  -Verbose

To test out this deployment, you can use a template like this one that creates a function app on Windows in a Consumption plan.

Next steps

Learn more about how to develop and configure Azure Functions.