TL;DR
- Azure Functions ends support for .NET 8 on November 10, 2026. .NET 9 expires the same day, so it is not a useful stepping stone. .NET 10 is supported through November 14, 2028.
- For an app already on the isolated worker model, this is nine steps and about an afternoon.
- Check your hosting plan first. .NET 10 does not run on the Linux Consumption plan.
- The most common failure is silent: the app deploys successfully and registers zero functions. The cause is almost always the Azure-side runtime version, which you have to set separately from your code.
If your Azure Functions app already runs on the isolated worker model, upgrading to .NET 10 is mostly configuration. The framework change itself is one line. What catches people is that the app has two halves — your deployed code and the platform's runtime configuration — and nothing warns you when they disagree. The build passes, the deployment reports success, and the function list comes back empty.
This guide walks the whole path: the plan check, the project and code changes, the Azure-side settings, and how to confirm you actually have a working .NET 10 function at the end.
Before you start: does your plan support .NET 10?
Check this first, because for some apps it turns a one-line change into a hosting migration. Microsoft states that .NET 9 is the last .NET version supported on the Linux Consumption plan and that newer versions aren't being added. Running .NET 10 requires Flex Consumption, Functions Premium, or a Dedicated App Service plan.
| Hosting plan | .NET 10? | Action |
|---|---|---|
| Flex Consumption | Yes | Proceed |
| Functions Premium | Yes | Proceed |
| Dedicated (App Service) | Yes | Proceed |
| Linux Consumption | No | Migrate to Flex Consumption first |
| Windows Consumption | No | Migrate to Flex, which also means moving to Linux |
To check what an app runs today:
az functionapp config show \
--name <APP_NAME> \
--resource-group <RESOURCE_GROUP> \
--query "{linuxFxVersion:linuxFxVersion, netFrameworkVersion:netFrameworkVersion}"
There is no in-place upgrade from Consumption to Flex. You create a new function app and redeploy, so treat it as a parallel rollout. Microsoft's az functionapp flex-migration command group automates most of it, and az functionapp flex-migration list sorts your apps into eligible and ineligible buckets. See Migrate Consumption plan apps to Flex Consumption.
One more prerequisite: you must be on the isolated worker model. The in-process model never received a .NET 10 update and reaches end of support on the same November 10, 2026 date. If FUNCTIONS_WORKER_RUNTIME is dotnet rather than dotnet-isolated, you have a larger migration ahead of this one — start with Microsoft's in-process to isolated guide.
The migration, step by step
Update the project file and packages, adjust Program.cs, refresh your build pipeline, then deploy to a staging slot, set the Azure-side runtime version, verify the function list, and swap. The optional Azure.Functions.Sdk project SDK replaces Microsoft.NET.Sdk plus the worker SDK package reference and removes several properties you previously set by hand.
1. Update the project file
<!-- Before -->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="2.52.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="2.0.7" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore" Version="2.1.0" />
</ItemGroup>
</Project>
<!-- After -->
<Project Sdk="Azure.Functions.Sdk/1.0.0">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="2.52.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore" Version="2.1.0" />
</ItemGroup>
</Project>
Keep the Microsoft.Azure.Functions.Worker reference explicit. That lets NuGet resolve the highest worker version across your dependency graph. If it goes missing after a restore, the SDK raises diagnostic AZFW0111. (Isolated worker process guide)
Adopting Azure.Functions.Sdk is optional. You can target net10.0 while keeping Microsoft.NET.Sdk and an explicit Microsoft.Azure.Functions.Worker.Sdk reference, which keeps the framework change and the SDK change independently revertible.
2. Meet the minimum package versions
The version numbers above are examples. These are the floors — below them the runtime will not load correctly:
| Package | Minimum version |
|---|---|
Microsoft.Azure.Functions.Worker |
2.50.0 |
Microsoft.Azure.Functions.Worker.Sdk |
2.0.5 |
Update your extension packages at the same time. Anything still on a 1.x worker line needs to move.
3. Update Program.cs
If you are still on the older HostBuilder pattern, switch to FunctionsApplication.CreateBuilder. It mirrors WebApplication.CreateBuilder(args) from ASP.NET Core and is built on HostApplicationBuilder, so service registration is direct rather than nested in a callback.
// Before
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.ConfigureServices(services =>
{
services.AddSingleton<IMyService, MyService>();
})
.Build();
await host.RunAsync();
// After
var builder = FunctionsApplication.CreateBuilder(args);
builder.ConfigureFunctionsWebApplication();
builder.Services.AddSingleton<IMyService, MyService>();
await builder.Build().RunAsync();
Pick the right configuration call. This is the one line here that will break an app if you get it wrong:
-
ConfigureFunctionsWebApplication()— for apps using ASP.NET Core HTTP integration. It wires up the ASP.NET Core middleware pipeline. -
ConfigureFunctionsWorkerDefaults()— for non-HTTP apps: queue triggers, timers, Service Bus, Event Grid.
Templates usually choose correctly for new projects. When you're migrating by hand, nothing checks it for you.
4. Search the whole repo for net8.0
Publish profiles, Dockerfiles, MSBuild conditions and any FunctionsWorkerToolPath property all hide copies of the old moniker. Changing TargetFramework does not touch them, and a stale path sends the build output somewhere the tooling isn't looking.
5. Update global.json and CI
Move the pinned SDK from 8.0.x to 10.0.x, and bump your runner setup (actions/setup-dotnet or the UseDotNet task) from 8.x to 10.x. A stale pin blocks the build outright and can also block dotnet tool installs that respect it.
6. If you build custom containers, check your base image
.NET 10 changed the default Linux distro for container images from Debian to Ubuntu. Microsoft documents this as a breaking change: default tags now reference Ubuntu 24.04 "Noble Numbat", and Debian-based images are no longer shipped for .NET 10 at all.
If your Dockerfile installs packages with apt-get, those package names may differ or not exist on Ubuntu. If you specifically need Debian, you now have to build and maintain that image yourself. (Default .NET container tags now use Ubuntu)
7. Test locally with Core Tools v4
Run the app and fire every trigger type. Pay particular attention to output bindings and serialization behaviour, which is where subtle differences surface.
8. Deploy to a staging slot and set the runtime version
This is the step people miss. Deploying your code does not change the platform's configured .NET version. Set it explicitly on the slot:
# Linux
az functionapp config set \
--name <APP_NAME> --resource-group <RESOURCE_GROUP> --slot staging \
--linux-fx-version "DOTNET-ISOLATED|10.0"
# Windows
az functionapp config set \
--name <APP_NAME> --resource-group <RESOURCE_GROUP> --slot staging \
--net-framework-version v10.0
Confirm the app settings while you're there: FUNCTIONS_EXTENSION_VERSION should be ~4 and FUNCTIONS_WORKER_RUNTIME should be dotnet-isolated.
9. Verify, then swap
Do not swap on a green deployment status. Check the function list:
az functionapp function list \
--name <APP_NAME> --resource-group <RESOURCE_GROUP> --slot staging \
--query "[].name" -o tsv
Every function should be listed. An empty or partial list means the worker failed to start or failed to register — see the next section. Then exercise at least one trigger of each type before swapping.
Three things that fail without an error
Microsoft Q&A documents the core symptom: an app can deploy and still fail at runtime, with functions not appearing or host startup failures. Three known causes:
| What happens | Cause | Fix |
|---|---|---|
| Deploy succeeds, function list empty | Azure-side .NET stack version doesn't match the deployed target framework | Step 8 above |
| CLI accepted the config, app broken | `az functionapp config set --linux-fx-version "DOTNET-ISOLATED\ | 10.0"` succeeds on Linux Consumption even though .NET 10 is only supported on Flex (azure-cli #32523) |
| Works locally, hangs in CI | Host startup can still require a visible .NET 8 runtime because the generated WorkerExtensions targets net8 (core-tools #5138) | Install .NET 8 alongside .NET 10 on the agent |
All three show up as a missing or partial function list in staging before they reach production — but only if someone checks.
If you already swapped and it's broken, swap back. That's the whole reason for the slot:
az functionapp deployment slot swap \
--name <APP_NAME> --resource-group <RESOURCE_GROUP> \
--slot staging --action swap
FAQ
Do my functions stop working on November 10, 2026?
No. End of support means no more security patches, bug fixes, or performance updates, and limited support options. Existing apps generally keep executing. The risk is an unpatched runtime sitting in production indefinitely, not an outage on the day.
Do I have to switch to FunctionsApplication.CreateBuilder?
Not strictly — existing HostBuilder code continues to work. But the new pattern is where the platform is heading, it aligns Functions startup with ASP.NET Core and Worker Services, and doing it during an upgrade you're already testing is cheaper than doing it later on its own.
Does this require changes to my function code?
Usually not to the function bodies. The work is in the project file, package versions, Program.cs, pipeline config, and the Azure-side runtime setting.
Is Azure.Functions.Sdk required?
No. You can target net10.0 while keeping Microsoft.NET.Sdk and an explicit worker SDK reference. Adopting the new project SDK separately keeps the two changes independently revertible.
About the author
Florian Lenz [Freelance Azure Cloud Engineer & Solutions Architect · Microsoft MVP]
Ten-plus years designing, building, and operating secure, scalable, enterprise-grade cloud systems on Microsoft Azure. Migrations like this one are part of the job: version upgrades, hosting plan moves, and the unglamorous cleanup that follows them.
Top comments (1)
One plan row looks worth revisiting: Microsoft’s current support note excludes .NET 10 specifically on Linux Consumption, so the blanket “No” for Windows Consumption appears broader than the documented restriction. I’d also make the staging check trigger-aware: a slot is a live app, so queue, timer, or Service Bus triggers can consume real work before the swap. Keep
AzureWebJobs.<FunctionName>.Disabled=trueslot-sticky—or point bindings at isolated sources—then enable it only for a controlled smoke test. A safer swap gate is: every function registered, every trigger bound to its intended source, and staging consumed no production work.