In this post, I’ll show you how to create a Bicep file which declares the resources required for an Azure Function App.

Prerequisites

I’ll be using Visual Studio Code as my editor, where I’ll be writing the .bicep file for this walkthrough. I’ll also be using the official Bicep extension.

I’ll be using the Azure Az PowerShell module to handle deploying the resources declared in the .bicep file I create. You can find instructions on installing the module at Microsoft Learn.

You’ll need to install Azure Bicep if you haven’t already.

The rest of this post assumes that you’ve already authenticated the Azure Az PowerShell module with an Azure account.

Creating an Azure resource group

Before we begin writing our Bicep code, we’ll create an Azure resource group using the Azure Az PowerShell module. Run the following command in a PowerShell session:

New-AzResourceGroup -Name rg-BicepFunctionAppDemo -Location uksouth

You’ll get a response back similar to the following (where <subscription_id> contains your own Azure subscription identifier):

ResourceGroupName : rg-BicepFunctionAppDemo
Location          : uksouth
ProvisioningState : Succeeded
Tags              :
ResourceId        : /subscriptions/<subscription_id>/resourceGroups/rg-BicepFunctionAppDemo

The Azure Function code

The Bicep file that we create shortly won’t only declare the resources for an Azure Function App, but it’ll also contain declarations necessary to deploy an Azure Function inside of this resource. For the purposes of this walkthrough, I’ve taken a copy of the default code populated when manually creating a new .NET Azure Function HTTP trigger. When triggered with no query parameters, this code simply responds with:

This HTTP triggered function executed successfully. Pass a name in the query
string or in the request body for a personalized response.

I’ve compressed the contents of this default code into a .zip file and uploaded it to my GitHub account. If you’re playing along, you can use the same default code found in this GitHub repository. A full copy of the Create-AzureFunctionApp.bicep file that we create below can also be found in the same GitHub repository.

Creating the .bicep file

Create a new file called Create-AzureFunctionApp.bicep. In this file, we’ll be declaring five different Azure resources:

  • an Azure Function App
  • an Azure Storage account (required by the Azure Function App)
  • a serverless Consumption hosting plan (required by the Azure Function App)
  • an Application Insights resource (allowing us to collect logs)
  • a zip deployment (allowing us to deploy our pre-packaged .zip file containing the code mentioned above).

I’ve decomposed the entire .bicep file into individual sections below, but you can also view the file in its entirety.

We’ll be passing two parameters when deploying the resources declared in this file. First, will be the Azure region that we want to deploy to, which we’ll give a parameter name of location. If not passed, this will default to the location of the associated Azure resource group:

@description('Location for all resources')
param location string = resourceGroup.location()

Our second parameter will allow us to pass the URL of the .zip file containing our default Azure Function code:

@description('Location of Azure Function .zip archive')
param packageUri string

We’ll create two variables for our Azure Function App name, and our Azure Storage account name:

var functionAppName = 'funcBicepFunctionAppDemo'
var storageAccountName = 'stbicepfunctionappdemo'

Declaring the Azure Storage account

resource storageAccount 'Microsoft.Storage/storageAccounts@2021-08-01' = {
  name: storageAccountName
  location: location
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'Storage'
}

Declaring the Azure serverless Consumption hosting plan

resource hostingPlan 'Microsoft.Web/serverfarms@2021-03-01' = {
  name: 'aseBicepFunctionAppDemo'
  location: location
  sku: {
    name: 'Y1'
    tier: 'Dynamic'
  }
  properties: {}
}

Declaring the Azure Function App

resource functionApp 'Microsoft.Web/sites@2021-03-01' = {
  name: functionAppName
  location: location
  kind: 'functionapp'
  identity: {
    type: 'SystemAssigned'
  }
  properties: {
    serverFarmId: hostingPlan.id
    siteConfig: {
      appSettings: [
        {
          name: 'AzureWebJobsStorage'
          value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccount.listKeys().keys[0].value}'
        }
        {
          name: 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING'
          value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccount.listKeys().keys[0].value}'
        }
        {
          name: 'FUNCTIONS_EXTENSION_VERSION'
          value: '~4'
        }
        {
          name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
          value: applicationInsights.properties.InstrumentationKey
        }
        {
          name: 'FUNCTIONS_WORKER_RUNTIME'
          value: 'dotnet'
        }
      ]
    }
    httpsOnly: true
  }
}

Declaring the Azure Application Insights resource

This resource isn’t strictly necessary, as it isn’t something that is mandatory when deploying a new Azure Function App.

resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = {
  name: 'appiBicepFunctionAppDemo'
  location: location
  kind: 'web'
  properties: {
    Application_Type: 'web'
    Request_Source: 'rest'
  }
}

Declaring the .zip deployment resource

It’s important that the packageUri property value matches the name that you give to the .zip file URL parameter mentioned earlier. For ease, I’ve given both the same name.

resource zipDeploy 'Microsoft.Web/sites/extensions@2022-03-01' = {
  parent: functionApp
  name: 'MSDeploy'
  properties: {
    packageUri: packageUri
  }
}

Deploying the resources declared in the .bicep file

If you don’t already have the Azure CLI installed, you can find an installation guide at Microsoft Learn.

To deploy the resources declared in our .bicep file, run the following command in a PowerShell session:

New-AzResourceGroupDeployment -ResourceGroupName rg-BicepFunctionAppDemo -TemplateFile ./Create-AzureFunctionApp.bicep -packageUri https://github.com/stuartmccoll/bicep-examples/raw/main/azure-function-app/BicepFunctionAppDemo.zip

You should receive a similar response to the following:

DeploymentName          : Create-AzureFunctionApp
ResourceGroupName       : rg-BicepFunctionAppDemo
ProvisioningState       : Succeeded
Timestamp               : 26/03/2023 13:31:22
Mode                    : Incremental
TemplateLink            :
Parameters              :
                          Name             Type                       Value
                          ===============  =========================  ==========
                          location         String                     "uksouth"
                          packageUri       String
                          "https://github.com/stuartmccoll/bicep-examples/raw/main/azure-function-app/BicepFunctionAppDemo.zip"

Outputs                 :
DeploymentDebugLogLevel :

You can validate that the deployment has been successful by running the following command in a PowerShell session:

Get-AzResource -ResourceGroupName rg-BicepFunctionAppDemo

If you navigate to the Azure function resource in your account, you’ll find a ‘Get Function Url’ button on the Overview screen. If you navigate to the URL, you should receive our expected response:

This HTTP triggered function executed successfully. Pass a name in the query
string or in the request body for a personalized response.

Removing resources

Finally, let’s remove the resources created. Run the following command in a PowerShell session:

Remove-AzResourceGroup -Name rg-BicepFunctionAppDemo

Further reading

If you’re interested in exploring Bicep further, you may be interested in the Fundamentals of Bicep learning path at Microsoft Learn.