Migrate apps from Azure Functions version 3.x to version 4.x

Azure Functions version 4.x is highly backwards compatible to version 3.x. Most apps should safely upgrade to 4.x without requiring significant code changes. For more information about Functions runtime versions, see Azure Functions runtime versions overview.

Important

Beginning on December 13, 2022, function apps running on versions 2.x and 3.x of the Azure Functions runtime have reached the end of life (EOL) of extended support.

After the deadline, function apps can be created and deployed from your CI/CD DevOps pipeline, and all existing apps continue to run without breaking changes. However, your apps are not eligible for new features, security patches, and performance optimizations. You'll get related service support once you upgraded them to version 4.x.

End of support for these runtime versions is due to the ending of support for .NET Core 3.1, which is required by these older runtime versions. This requirement affects all languages supported by Azure Functions.

We highly recommend you migrating your function apps to version 4.x of the Functions runtime by following this article.

Functions version 1.x is still supported for C# function apps that require the .NET Framework. Preview support is now available in Functions 4.x to run C# functions on .NET Framework 4.8.

This article walks you through the process of safely migrating your function app to run on version 4.x of the Functions runtime. Because project upgrade instructions are language dependent, make sure to choose your development language from the selector at the top of the article.

Choose your target .NET

On version 3.x of the Functions runtime, your C# function app targets .NET Core 3.1. When you migrate your function app to version 4.x, you have the opportunity to choose the target version of .NET. You can upgrade your C# project to one of the following versions of .NET, all of which can run on Functions version 4.x:

.NET version Process model*
.NET 7 Isolated worker process
.NET 6 Isolated worker process
.NET 6 In-process

* In-process execution is only supported for Long Term Support (LTS) releases of .NET. Standard Terms Support (STS) releases and .NET Framework are supported .NET Azure functions isolated worker process.

Tip

On version 3.x of the Functions runtime, if you're on .NET 5, we recommend you upgrade to .NET 7. If you're on .NET Core 3.1, we recommend you upgrade to .NET 6 (in-process) for a quick upgrade path.

If you're looking for moving to a Long Term Support (LTS) .NET release, we recommend you upgrade to .NET 6 .

Migrating to .NET Isolated worker model to get all benefits provided by Azure Functions .NET isolated worker process. For more information about .NET isolated worker process advantages see .NET isolated worker process enhancement. For more information about .NET version support, see Supported versions.

Upgrading from .NET Core 3.1 to .NET 6 running in-process requires minimal updates to your project and virtually no updates to code. Switching to the isolated worker process model requires you to make changes to your code, but provides the flexibility of being able to easily run on any future version of .NET. For a feature and functionality comparison between the two process models, see Differences between in-process and isolate worker process .NET Azure Functions.

Prepare for migration

Before you upgrade your app to version 4.x of the Functions runtime, you should do the following tasks:

Run the pre-upgrade validator

Azure Functions provides a pre-upgrade validator to help you identify potential issues when migrating your function app to 4.x. To run the pre-upgrade validator:

  1. In the Azure portal, navigate to your function app.

  2. Open the Diagnose and solve problems page.

  3. In Function App Diagnostics, start typing Functions 4.x Pre-Upgrade Validator and then choose it from the list.

  4. After validation completes, review the recommendations and address any issues in your app. If you need to make changes to your app, make sure to validate the changes against version 4.x of the Functions runtime, either locally using Azure Functions Core Tools v4 or by using a staging slot.

Identify function apps to upgrade

Use the following PowerShell script to generate a list of function apps in your subscription that currently target versions 2.x or 3.x:

$Subscription = '<YOUR SUBSCRIPTION ID>' 
 
Set-AzContext -Subscription $Subscription | Out-Null

$FunctionApps = Get-AzFunctionApp

$AppInfo = @{}

foreach ($App in $FunctionApps)
{
     if ($App.ApplicationSettings["FUNCTIONS_EXTENSION_VERSION"] -like '*3*')
     {
          $AppInfo.Add($App.Name, $App.ApplicationSettings["FUNCTIONS_EXTENSION_VERSION"])
     }
}

$AppInfo

Upgrade your local project

Upgrading instructions are language dependent. If you don't see your language, choose it from the selector at the top of the article.

Choose the tab that matches your target version of .NET and the desired process model (in-process or isolated worker process).

.csproj file

The following example is a .csproj project file that uses .NET Core 3.1 on version 3.x:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <AzureFunctionsVersion>v3</AzureFunctionsVersion>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.13" />
  </ItemGroup>
  <ItemGroup>
    <Reference Include="Microsoft.CSharp" />
  </ItemGroup>
  <ItemGroup>
    <None Update="host.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="local.settings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CopyToPublishDirectory>Never</CopyToPublishDirectory>
    </None>
  </ItemGroup>
</Project>

Use one of the following procedures to update this XML file to run in Functions version 4.x:

The following changes are required in the .csproj XML project file:

  1. Change the value of PropertyGroup.TargetFramework to net6.0.

  2. Change the value of PropertyGroup.AzureFunctionsVersion to v4.

  3. Replace the existing ItemGroup.PackageReference list with the following ItemGroup:

    <ItemGroup>
      <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.1.1" />
    </ItemGroup>
    

After you make these changes, your updated project should look like the following example:


<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <AzureFunctionsVersion>v4</AzureFunctionsVersion>
    <RootNamespace>My.Namespace</RootNamespace>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.1.1" />
  </ItemGroup>
  <ItemGroup>
    <None Update="host.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="local.settings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CopyToPublishDirectory>Never</CopyToPublishDirectory>
    </None>
  </ItemGroup>
</Project>

program.cs file

When migrating to run in an isolated worker process, you must add the following program.cs file to your project:

A program.cs file isn't required when running in-process.

local.settings.json file

The local.settings.json file is only used when running locally. For information, see Local settings file. When migrating from running in-process to running in an isolated worker process, you need to change the FUNCTIONS_WORKER_RUNTIME value, as in the following example:

{
    "IsEncrypted": false,
    "Values": {
        "AzureWebJobsStorage": "AzureWebJobsStorageConnectionStringValue",
        "FUNCTIONS_WORKER_RUNTIME": "dotnet"
    }
}

Namespace changes

C# functions that run in an isolated worker process uses libraries in a different namespace than those libraries used when running in-process. In-process libraries are generally in the namespace Microsoft.Azure.WebJobs.*. Isolated worker process function apps use libraries in the namespace Microsoft.Azure.Functions.Worker.*. You can see the effect of these namespace changes on using statements in the HTTP trigger template examples that follow.

Class name changes

Some key classes change names as a result of differences between in-process and isolated worker process APIs.

The following table indicates key .NET classes used by Functions that could change when migrating from in-process:

.NET Core 3.1 .NET 6 (in-process) .NET 6 (isolated) .NET 7
FunctionName (attribute) FunctionName (attribute) Function (attribute) Function (attribute)
HttpRequest HttpRequest HttpRequestData HttpRequestData
OkObjectResult OkObjectResult HttpResponseData HttpResponseData

There might also be class name differences in bindings. For more information, see the reference articles for the specific bindings.

HTTP trigger template

The differences between in-process and isolated worker process can be seen in HTTP triggered functions. The HTTP trigger template for version 3.x (in-process) looks like the following example:

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace Company.Function
{
    public static class HttpTriggerCSharp
    {
        [FunctionName("HttpTriggerCSharp")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.AuthLevelValue, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");

            string name = req.Query["name"];

            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
            dynamic data = JsonConvert.DeserializeObject(requestBody);
            name = name ?? data?.name;

            string responseMessage = string.IsNullOrEmpty(name)
                ? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
                : $"Hello, {name}. This HTTP triggered function executed successfully.";

            return new OkObjectResult(responseMessage);
        }
    }
}

The HTTP trigger template for the migrated version looks like the following example:

Sames as version 3.x (in-process).

To update your project to Azure Functions 4.x:

  1. Update your local installation of Azure Functions Core Tools to version 4.x.

  2. Update your app's Azure Functions extensions bundle to 2.x or above. For more information, see breaking changes.

  1. If needed, move to one of the Java versions supported on version 4.x.

  2. Update the app's POM.xml file to modify the FUNCTIONS_EXTENSION_VERSION setting to ~4, as in the following example:

    <configuration>
        <resourceGroup>${functionResourceGroup}</resourceGroup>
        <appName>${functionAppName}</appName>
        <region>${functionAppRegion}</region>
        <appSettings>
            <property>
                <name>WEBSITE_RUN_FROM_PACKAGE</name>
                <value>1</value>
            </property>
            <property>
                <name>FUNCTIONS_EXTENSION_VERSION</name>
                <value>~4</value>
            </property>
        </appSettings>
    </configuration>
    
  1. If needed, move to one of the Node.js versions supported on version 4.x.
  1. Take this opportunity to upgrade to PowerShell 7.2, which is recommended. For more information, see PowerShell versions.
  1. If you're using Python 3.6, move to one of the supported versions.

Upgrade your function app in Azure

You need to upgrade the runtime of the function app host in Azure to version 4.x before you publish your migrated project. The runtime version used by the Functions host is controlled by the FUNCTIONS_EXTENSION_VERSION application setting, but in some cases other settings must also be updated. Both code changes and changes to application settings require your function app to restart.

The easiest way is to upgrade without slots and then republish your app project. You can also minimize the downtime in your app and simplify rollback by upgrading using slots.

Upgrade without slots

The simplest way to upgrade to v4.x is to set the FUNCTIONS_EXTENSION_VERSION application setting to ~4 on your function app in Azure. You must follow a different procedure on a site with slots.

az functionapp config appsettings set --settings FUNCTIONS_EXTENSION_VERSION=~4 -g <RESOURCE_GROUP_NAME> -n <APP_NAME>

During upgrade, you must also set another setting, which differs between Windows and Linux.

When running on Windows, you also need to enable .NET 6.0, which is required by version 4.x of the runtime.

az functionapp config set --net-framework-version v6.0 -g <RESOURCE_GROUP_NAME> -n <APP_NAME>

.NET 6 is required for function apps in any language running on Windows.

In this example, replace <APP_NAME> with the name of your function app and <RESOURCE_GROUP_NAME> with the name of the resource group.

You can now republish your app project that has been migrated to run on version 4.x.

Upgrade using slots

Using deployment slots is a good way to upgrade your function app to the v4.x runtime from a previous version. By using a staging slot, you can run your app on the new runtime version in the staging slot and switch to production after verification. Slots also provide a way to minimize downtime during upgrade. If you need to minimize downtime, follow the steps in Minimum downtime upgrade.

After you've verified your app in the upgraded slot, you can swap the app and new version settings into production. This swap requires setting WEBSITE_OVERRIDE_STICKY_EXTENSION_VERSIONS=0 in the production slot. How you add this setting affects the amount of downtime required for the upgrade.

Standard upgrade

If your slot-enabled function app can handle the downtime of a full restart, you can update the WEBSITE_OVERRIDE_STICKY_EXTENSION_VERSIONS setting directly in the production slot. Because changing this setting directly in the production slot causes a restart that impacts availability, consider doing this change at a time of reduced traffic. You can then swap in the upgraded version from the staging slot.

The Update-AzFunctionAppSetting PowerShell cmdlet doesn't currently support slots. You must use Azure CLI or the Azure portal.

  1. Use the following command to set WEBSITE_OVERRIDE_STICKY_EXTENSION_VERSIONS=0 in the production slot:

    az functionapp config appsettings set --settings WEBSITE_OVERRIDE_STICKY_EXTENSION_VERSIONS=0  -g <RESOURCE_GROUP_NAME>  -n <APP_NAME> 
    

    In this example, replace <APP_NAME> with the name of your function app and <RESOURCE_GROUP_NAME> with the name of the resource group. This command causes the app running in the production slot to restart.

  2. Use the following command to also set WEBSITE_OVERRIDE_STICKY_EXTENSION_VERSIONS in the staging slot:

    az functionapp config appsettings set --settings WEBSITE_OVERRIDE_STICKY_EXTENSION_VERSIONS=0 -g <RESOURCE_GROUP_NAME>  -n <APP_NAME> --slot <SLOT_NAME>
    
  3. Use the following command to change FUNCTIONS_EXTENSION_VERSION and upgrade the staging slot to the new runtime version:

    az functionapp config appsettings set --settings FUNCTIONS_EXTENSION_VERSION=~4 -g <RESOURCE_GROUP_NAME>  -n <APP_NAME> --slot <SLOT_NAME>
    
  4. Version 4.x of the Functions runtime requires .NET 6 in Windows. On Linux, .NET apps must also upgrade to .NET 6. Use the following command so that the runtime can run on .NET 6:

    When running on Windows, you also need to enable .NET 6.0, which is required by version 4.x of the runtime.

    az functionapp config set --net-framework-version v6.0 -g <RESOURCE_GROUP_NAME> -n <APP_NAME>
    

    .NET 6 is required for function apps in any language running on Windows.

    In this example, replace <APP_NAME> with the name of your function app and <RESOURCE_GROUP_NAME> with the name of the resource group.

  5. If your code project required any updates to run on version 4.x, deploy those updates to the staging slot now.

  6. Confirm that your function app runs correctly in the upgraded staging environment before swapping.

  7. Use the following command to swap the upgraded staging slot to production:

    az functionapp deployment slot swap -g <RESOURCE_GROUP_NAME>  -n <APP_NAME> --slot <SLOT_NAME> --target-slot production
    

Minimum downtime upgrade

To minimize the downtime in your production app, you can swap the WEBSITE_OVERRIDE_STICKY_EXTENSION_VERSIONS setting from the staging slot into production. After that, you can swap in the upgraded version from a prewarmed staging slot.

  1. Use the following command to set WEBSITE_OVERRIDE_STICKY_EXTENSION_VERSIONS=0 in the staging slot:

    az functionapp config appsettings set --settings WEBSITE_OVERRIDE_STICKY_EXTENSION_VERSIONS=0 -g <RESOURCE_GROUP_NAME>  -n <APP_NAME> --slot <SLOT_NAME>
    
  2. Use the following commands to swap the slot with the new setting into production, and at the same time restore the version setting in the staging slot.

    az functionapp deployment slot swap -g <RESOURCE_GROUP_NAME>  -n <APP_NAME> --slot <SLOT_NAME> --target-slot production
    az functionapp config appsettings set --settings FUNCTIONS_EXTENSION_VERSION=~3 -g <RESOURCE_GROUP_NAME>  -n <APP_NAME> --slot <SLOT_NAME>
    

    You may see errors from the staging slot during the time between the swap and the runtime version being restored on staging. This error can happen because having WEBSITE_OVERRIDE_STICKY_EXTENSION_VERSIONS=0 only in staging during a swap removes the FUNCTIONS_EXTENSION_VERSION setting in staging. Without the version setting, your slot is in a bad state. Updating the version in the staging slot right after the swap should put the slot back into a good state, and you call roll back your changes if needed. However, any rollback of the swap also requires you to directly remove WEBSITE_OVERRIDE_STICKY_EXTENSION_VERSIONS=0 from production before the swap back to prevent the same errors in production seen in staging. This change in the production setting would then cause a restart.

  3. Use the following command to again set WEBSITE_OVERRIDE_STICKY_EXTENSION_VERSIONS=0 in the staging slot:

    az functionapp config appsettings set --settings WEBSITE_OVERRIDE_STICKY_EXTENSION_VERSIONS=0 -g <RESOURCE_GROUP_NAME>  -n <APP_NAME> --slot <SLOT_NAME>
    

    At this point, both slots have WEBSITE_OVERRIDE_STICKY_EXTENSION_VERSIONS=0 set.

  4. Use the following command to change FUNCTIONS_EXTENSION_VERSION and upgrade the staging slot to the new runtime version:

    az functionapp config appsettings set --settings FUNCTIONS_EXTENSION_VERSION=~4 -g <RESOURCE_GROUP_NAME>  -n <APP_NAME> --slot <SLOT_NAME>
    
  5. Version 4.x of the Functions runtime requires .NET 6 in Windows. On Linux, .NET apps must also upgrade to .NET 6. Use the following command so that the runtime can run on .NET 6:

    When running on Windows, you also need to enable .NET 6.0, which is required by version 4.x of the runtime.

    az functionapp config set --net-framework-version v6.0 -g <RESOURCE_GROUP_NAME> -n <APP_NAME>
    

    .NET 6 is required for function apps in any language running on Windows.

    In this example, replace <APP_NAME> with the name of your function app and <RESOURCE_GROUP_NAME> with the name of the resource group.

  6. If your code project required any updates to run on version 4.x, deploy those updates to the staging slot now.

  7. Confirm that your function app runs correctly in the upgraded staging environment before swapping.

  8. Use the following command to swap the upgraded and prewarmed staging slot to production:

    az functionapp deployment slot swap -g <RESOURCE_GROUP_NAME>  -n <APP_NAME> --slot <SLOT_NAME> --target-slot production
    

Breaking changes between 3.x and 4.x

The following are key breaking changes to be aware of before upgrading a 3.x app to 4.x, including language-specific breaking changes. For a full list, see Azure Functions GitHub issues labeled Breaking Change: Approved.

If you don't see your programming language, go select it from the top of the page.

Runtime

  • Azure Functions proxies is a legacy feature for versions 1.x through 3.x of the Azure Functions runtime. Support for Functions proxies can be re-enabled in version 4.x so that you can successfully upgrade your function apps to the latest runtime version. As soon as possible, you should instead switch to integrating your function apps with Azure API Management. API Management lets you take advantage of a more complete set of features for defining, securing, managing, and monetizing your Functions-based APIs. For more information, see API Management integration. To learn how to re-enable proxies support in Functions version 4.x, see Re-enable proxies in Functions v4.x.

  • Logging to Azure Storage using AzureWebJobsDashboard is no longer supported in 4.x. You should instead use Application Insights. (#1923)

  • Azure Functions 4.x now enforces minimum version requirements for extensions. Upgrade to the latest version of affected extensions. For non-.NET languages, upgrade to extension bundle version 2.x or later. (#1987)

  • Default and maximum timeouts are now enforced in 4.x for function apps running on Linux in a Consumption plan. (#1915)

  • Azure Functions 4.x uses Azure.Identity and Azure.Security.KeyVault.Secrets for the Key Vault provider and has deprecated the use of Microsoft.Azure.KeyVault. For more information about how to configure function app settings, see the Key Vault option in Secret Repositories. (#2048)

  • Function apps that share storage accounts now fail to start when their host IDs are the same. For more information, see Host ID considerations. (#2049)

  • Azure Functions 4.x supports .NET 6 in-process and isolated apps.

  • InvalidHostServicesException is now a fatal error. (#2045)

  • EnableEnhancedScopes is enabled by default. (#1954)

  • Remove HttpClient as a registered service. (#1911)

  • Use single class loader in Java 11. (#1997)

  • Stop loading worker jars in Java 8. (#1991)

  • Node.js versions 10 and 12 aren't supported in Azure Functions 4.x. (#1999)

  • Output serialization in Node.js apps was updated to address previous inconsistencies. (#2007)

  • Default thread count has been updated. Functions that aren't thread-safe or have high memory usage may be impacted. (#1962)
  • Python 3.6 isn't supported in Azure Functions 4.x. (#1999)

  • Shared memory transfer is enabled by default. (#1973)

  • Default thread count has been updated. Functions that aren't thread-safe or have high memory usage may be impacted. (#1962)

Next steps