Avoiding cold start delays in Azure Function apps written with .NET
Posted: (EET/GMT+2)
Azure Function apps are today a very common way to implement distributed applications. But, as in all distributed systems, performance issues can quickly degrade the usability of such solutions. Azure Functions don't necessarily run 24/7, as by default they are managed by the Azure environment.
Especially if your Azure Function app feels slow on the first request, you are likely hitting what is called a cold start. Here are a few practical ways to reduce or avoid that delay in .NET-based functions.
A cold start happens when the function host is not running and needs to start from scratch. This includes loading the runtime, initializing dependencies, and starting your code. On the Consumption plan, this can add noticeable latency to the first request.
The simplest way to avoid cold starts is to use a plan where the app stays warm:
- Consumption plan: can scale to zero, cold starts possible
- Premium plan: pre-warmed instances, reduced cold starts
- Dedicated (App Service): always on, no cold start when correctly configured.
On the Dedicated plan, make sure the "Always On" option is enabled:
az webapp config set \ --name <function-app-name> \ --resource-group <resource-group> \ --always-on true
If you are using the Premium plan, configure at least one pre-warmed instance:
az functionapp plan update \ --name <plan-name> \ --resource-group <resource-group> \ --min-instances 1
If you need to stay on the Consumption plan, you can still reduce the impact by keeping the function warm with a timer trigger. For example:
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;
public class WarmupFunction
{
private readonly ILogger _logger;
public WarmupFunction(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<WarmupFunction>();
}
[Function("WarmupFunction")]
public void Run([TimerTrigger("0 */5 * * * *")] TimerInfo timer)
{
_logger.LogInformation("Warmup trigger executed");
}
}
The above code runs every 5 minutes and helps keep the host process alive. It does not guarantee zero cold starts, but it reduces how often they happen.
Here are a few practical tips for .NET functions:
- Keep startup code light. Avoid heavy work in constructors or static initializers.
-
Reuse clients like
HttpClientand database connections via dependency injection. - Avoid loading large assemblies or configuration files unless needed.
- Prefer async I/O to avoid blocking during initialization.
Also note that deployment matters. Large deployments and many dependencies can increase startup time because the runtime has more to load before handling the first request.
In practice, the most reliable solution is to use Premium or Dedicated plans when latency matters. Timer-based warmup helps, but it is still a workaround.