Azure Functions .NET in-process model ends on 10 November 2026: the migration checklist
Support for the Azure Functions .NET in-process model ends on 10 November 2026. This migration checklist finds the apps that still use it, converts the project, packages, Program.cs, bindings and logging to the isolated worker model, and deploys through a staging slot without an outage.
Apps & integrationFix a problem8 min read
On 10 November 2026, Microsoft's support for the .NET in-process model in Azure Functions ends. Apps that still use it keep running after that date, but they stop getting security updates and bug fixes, and Microsoft's support may ask you to reproduce a problem on the supported model before helping. The replacement, the isolated worker model, runs your code in its own process, works with every current .NET version, and is the only .NET model the Flex Consumption plan accepts. The migration is mostly mechanical. This checklist walks through it in the order that produces the fewest surprises.
What changes, in one table
| In-process model | Isolated worker model | |
|---|---|---|
| Where your code runs | Inside the Functions host process | In a separate .NET worker process |
| .NET versions | LTS only, ending with .NET 8 | .NET 8, 9, 10 and .NET Framework 4.8 |
| Project SDK | Microsoft.NET.Sdk.Functions | Azure.Functions.Sdk plus Microsoft.Azure.Functions.Worker |
| Binding packages | Microsoft.Azure.WebJobs.Extensions.* | Microsoft.Azure.Functions.Worker.Extensions.* |
| Start-up | A FunctionsStartup class | Program.cs with a HostBuilder |
| Output bindings | Return value, out parameters, IAsyncCollector | Return value; several outputs through a class with attributed properties |
Imperative bindings (IBinder) | Supported | Not supported; use the service SDK directly |
| Middleware | No | Yes |
| JSON by default | Newtonsoft.Json | System.Text.Json |
| Flex Consumption plan | Not supported | Supported |
| Support | Ends 10 November 2026 | Current |
The FUNCTIONS_WORKER_RUNTIME setting tells them apart: dotnet is in-process, dotnet-isolated is the worker model.
Find the apps that still run in-process
Run this in Azure PowerShell against each subscription (Set-AzContext -Subscription '<id>' to switch). Every app it lists has the dotnet runtime and needs migrating; apps already on dotnet-isolated don't appear.
$FunctionApps = Get-AzFunctionApp
$AppInfo = @{}
foreach ($App in $FunctionApps) {
if ($App.Runtime -eq 'dotnet') { $AppInfo.Add($App.Name, $App.Runtime) }
}
$AppInfo
Two checks before you touch code:
- The Functions runtime must be 4.x. Apps on 1.x, 2.x or 3.x go through Microsoft's host-version migration guides first; those guides move you to the isolated model as you go.
- Pick the target .NET. If the app and its libraries run on modern .NET, target .NET 10. If something depends on .NET Framework-only APIs, target .NET Framework 4.8, which the isolated model supports and the in-process model never did. C# script apps (
.csx) must become a project first. Moving to .NET 10 also lets the .NET Upgrade Assistant make many of the edits below for you.
Convert the project
1. The project file
Replace the SDK and the framework, swap the core packages, and add the ExecutionContext alias (an ASP.NET Core type would otherwise shadow the Functions one):
<Project Sdk="Azure.Functions.Sdk/1.0.0">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="2.52.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore" Version="2.1.0" />
<PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.22.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.ApplicationInsights" Version="1.2.0" />
</ItemGroup>
<ItemGroup>
<Using Include="System.Threading.ExecutionContext" Alias="ExecutionContext" />
</ItemGroup>
</Project>
For .NET Framework 4.8 the target is net48, the HTTP package is Microsoft.Azure.Functions.Worker.Extensions.Http (ASP.NET Core types aren't available there), and a <Folder Include="Properties\" /> item replaces the alias. Build errors appear at this point; the next steps clear them.
2. Every binding package
Each Microsoft.Azure.WebJobs.Extensions.* package has a Microsoft.Azure.Functions.Worker.Extensions.* twin. The ones most apps hit:
| You had | You need |
|---|---|
Microsoft.NET.Sdk.Functions | Gone; the SDK and worker packages above replace it |
| A timer trigger (no package before) | …Worker.Extensions.Timer |
…WebJobs.Extensions.Storage | …Worker.Extensions.Storage.Blobs, .Storage.Queues and .Tables, as needed |
…WebJobs.Extensions.CosmosDB or .DocumentDB | …Worker.Extensions.CosmosDB |
…WebJobs.Extensions.ServiceBus | …Worker.Extensions.ServiceBus (host.json settings changed between 4.x and 5.x) |
…WebJobs.Extensions.EventHubs, .EventGrid, .SignalRService, .SendGrid, .Kafka, .RabbitMQ | The same name under …Worker.Extensions. |
…WebJobs.Extensions.DurableTask | …Worker.Extensions.DurableTask (and .SqlServer or .Netherite for those storage providers) |
Microsoft.Azure.Functions.Extensions (dependency injection) | Remove it; the worker has dependency injection built in |
When you're done, nothing in the project should reference Microsoft.Azure.WebJobs.* or Microsoft.Azure.Functions.Extensions. Take the chance to move any old Azure SDK packages to their Azure.* versions too, which the new extensions expect.
3. Program.cs replaces Startup.cs
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
var host = new HostBuilder()
.ConfigureFunctionsWebApplication()
.ConfigureServices(services =>
{
services.AddApplicationInsightsTelemetryWorkerService();
services.ConfigureFunctionsApplicationInsights();
// Everything that was in FunctionsStartup.Configure goes here.
})
.Build();
host.Run();
ConfigureFunctionsWebApplication() turns on ASP.NET Core integration, which gives HTTP triggers the familiar HttpRequest and IActionResult types and better performance. If you have no HTTP triggers you can use ConfigureFunctionsWorkerDefaults() instead, but keep the ASP.NET Core framework reference either way; Microsoft recommends it for performance. On .NET Framework use ConfigureFunctionsWorkerDefaults() and the HttpRequestData/HttpResponseData types. Delete the FunctionsStartup class once its registrations have moved.
4. Every function signature
For each function:
[FunctionName("X")]becomes[Function("X")]. Same signature; a find-and-replace does it.- Logging. The
ILogger logparameter is gone. InjectILogger<MyFunction>through the constructor and use the field instead. - Usings. Remove
using Microsoft.Azure.WebJobs;; addusing Microsoft.Azure.Functions.Worker;. - Attribute names. Triggers keep their names (
QueueTrigger,HttpTrigger). Input bindings gainInput(CosmosDB→CosmosDBInput); output bindings gainOutput(Queue→QueueOutput,Blob→BlobOutput). Some parameters go, for example theFileAccessargument on a blob output. - Outputs leave the parameter list. One output: put the attribute on the return type. Several: return a class whose properties carry the attributes.
IAsyncCollector<T>becomes an array,T[], or a client object you inject. IBindergoes. Replace it with the service's SDK client, injected throughProgram.cs.- HTTP streams become asynchronous. With ASP.NET Core integration,
ReadToEnd,WriteandFlushon the request and response throwInvalidOperationException: Synchronous operations are disallowed. Use theAsyncversions and returnTask<IActionResult>.
Before and after, for the simplest HTTP function:
// In-process
[FunctionName("Hello")]
public static IActionResult Run(
[HttpTrigger(AuthorizationLevel.Function, "get")] HttpRequest req, ILogger log)
{
log.LogInformation("Request received.");
return new OkObjectResult($"Hello, {req.Query["name"]}!");
}
// Isolated worker, .NET 10
public class Hello(ILogger<Hello> logger)
{
[Function("Hello")]
public IActionResult Run([HttpTrigger(AuthorizationLevel.Function, "get")] HttpRequest req)
{
logger.LogInformation("Request received.");
return new OkObjectResult($"Hello, {req.Query["name"]}!");
}
}
5. Local settings
In local.settings.json, FUNCTIONS_WORKER_RUNTIME becomes dotnet-isolated. host.json needs no change, but read the next section about what it no longer controls.
The behaviour changes that bite
- JSON. The worker uses System.Text.Json. It silently ignores Newtonsoft attributes such as
[JsonProperty]and[JsonIgnore], binding the property to its default value with no error. Replace them with[JsonPropertyName]and friends, or configure Newtonsoft as the worker's serialiser inProgram.csthroughWorkerOptions.Serializer. - Log levels.
host.jsonnow filters only the host's own logs. Filtering for logs from your code belongs inProgram.cs; without it, categories can appear at different levels in Application Insights than before. - Configuration sources registered in
HostBuilderapply to your code only. Trigger and binding settings still have to come from application settings, Key Vault references or App Configuration references. - Durable Functions has its own mapping:
IDurableOrchestrationContext→TaskOrchestrationContext(withcontext.CreateReplaySafeLogger()),IDurableOrchestrationClient→DurableTaskClient,StartNewAsync→ScheduleNewOrchestrationInstanceAsync,RetryOptions+CallActivityWithRetryAsync→TaskOptionson the normalCallActivityAsync, and entities become classes dispatched withTaskEntityDispatcher. Two defaults flip:ContinueAsNewnow preserves unprocessed events, andRestartAsyncno longer generates a new instance ID. Entity proxies and cross-task-hub overloads are gone, and orchestration history moves toGetOrchestrationHistoryAsync. Your storage provider settings are unchanged. - Cold starts are no longer tuned for you; the worker guide lists optimisations such as ReadyToRun. On Flex Consumption, always-ready instances remove the problem for a price.
Run func start with Azure Functions Core Tools 4.x and exercise every trigger before you deploy.
Deploy without an outage
Two things have to change in Azure, and they can't change in the same instant: the FUNCTIONS_WORKER_RUNTIME setting to dotnet-isolated, and the deployed code. Between the two, the app logs AZFD0013, a runtime and payload mismatch, and fails requests. So don't do it in the production slot.
- Create a staging slot (Premium and Dedicated plans have them; a Consumption plan allows one extra).
- In the staging slot only, set
FUNCTIONS_WORKER_RUNTIMEtodotnet-isolated. Don't mark it as a slot setting, so it travels with the swap. If you're also changing .NET version, update the stack configuration too, and update any pipeline or Bicep that sets either value, or the next deployment puts them back. - Publish the migrated project to the staging slot. Visual Studio offers to update the runtime setting during publish; it's still two operations, and the staging logs show the mismatch error briefly.
- Test in the slot until the errors stop and every trigger works.
- Swap. A swap is one atomic update, so production never sees the mismatch.
- Verify production, then repeat for the next app on your list.
az functionapp config appsettings set --name <app> --resource-group <rg> --slot staging \
--settings FUNCTIONS_WORKER_RUNTIME=dotnet-isolated
az functionapp config set --name <app> --resource-group <rg> --slot staging --net-framework-version v10.0
If the app runs on Linux Consumption, there's a second deadline behind this one: that plan retires on 30 September 2028, and .NET 10 can't run on it at all. Our guide to Azure Functions hosting plans explains the move to Flex Consumption, which only accepts the isolated model, so this migration comes first.
Sources
- Migrate C# apps from the in-process model to the isolated worker model, Microsoft Learn
- Differences between the isolated worker model and the in-process model, Microsoft Learn
- Migrate your Durable Functions app from in-process to isolated worker model, Microsoft Learn
- Guide for running C# Azure Functions in the isolated worker model, Microsoft Learn
- Azure Functions hosting options, Microsoft Learn (slots per plan; the Linux Consumption retirement)
Did this fix it?
Comments
No comments yet. Share what worked for you.
Sign in to comment. Comments show under a display name you choose, never your email.