← Back to all posts

Azure Functions HTTP in .NET

Azure Functions HTTP in .NET

Reading Time: 7 minutes

The Problem

Small APIs tend to start simple and then grow a cost and operations tail.

A standard deployed API - whether on Azure App Service, Azure Container Apps, or a VM - runs continuously. You pay for that compute whether it serves one request a minute or ten thousand. You manage application lifecycle, scaling configuration, runtime upgrades, and availability. For many workloads that is entirely appropriate. For others it is overhead that delivers no real value.

At the same time, teams sometimes reach for Azure Functions HTTP triggers for the wrong reasons. Choosing serverless for a high-throughput, latency-sensitive public API because it sounds modern is a different kind of mistake - one that shows up as unpredictable cold starts, vendor-managed concurrency ceilings, and unexpected billing.

The core problem is knowing when serverless HTTP is the right shape and when it is not.

The Solution

Azure Functions HTTP triggers give you a way to expose HTTP endpoints without the standing infrastructure of a full hosting plan. You write a function, configure a trigger, and Azure manages invocation, scaling, and lifecycle.

The right decision depends on:

  • how often the endpoint is called
  • how tolerant you are of cold starts
  • whether you need fine control over the runtime environment
  • what the cost profile looks like at your actual scale

Used in the right context, Azure Functions HTTP is a clean, low-maintenance option. Used in the wrong context, it introduces latency surprises, cost surprises, and operational friction.

What Azure Functions HTTP Actually Does

An Azure Functions HTTP trigger maps an HTTP request to a function invocation.

The function:

  • handles one request at a time per instance by default
  • can scale horizontally on the Consumption plan based on demand
  • is cold when idle and may take time to start on first request
  • returns an HTTP response like any normal API endpoint

From the caller’s perspective, it is just an HTTP endpoint. From the hosting perspective, it is fundamentally different from an always-on process.

Isolated Process vs In-Process

This is one of the most important choices when writing Azure Functions in .NET today.

In-Process (legacy)

In-Process means your function code runs inside the Azure Functions host process.

That gave tight integration in earlier .NET versions but came with significant constraints:

  • tightly coupled to the Functions host runtime version
  • limited compatibility with newer .NET releases
  • harder to use middleware and DI patterns that are standard in modern ASP.NET Core apps
  • the host process and your code share a single process, making isolation harder

In-Process hosting is being retired. Microsoft has announced end of support and strongly recommends migration.

Isolated Process (current standard)

Isolated Process means your function code runs in a separate worker process from the Azure Functions host.

That separation gives you:

  • full .NET SDK version flexibility
  • standard ASP.NET Core middleware patterns
  • a clean DI model that matches what you use in other .NET apps
  • better long-term support alignment with .NET release cycles
  • easier local testing and debugging

For all new functions, use Isolated Process. If you have existing In-Process functions, plan the migration.

A Simple Isolated Process HTTP Function

dotnet new func --worker-runtime dotnet-isolated

Program.cs uses the standard host builder pattern:

using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

var host = new HostBuilder()
    .ConfigureFunctionsWebApplication()
    .ConfigureServices(services =>
    {
        services.AddApplicationInsightsTelemetryWorkerService();
        services.ConfigureFunctionsApplicationInsights();
    })
    .Build();

await host.RunAsync();

A simple HTTP function:

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;

public class GreetFunction
{
    private readonly ILogger<GreetFunction> _logger;

    public GreetFunction(ILogger<GreetFunction> logger)
    {
        _logger = logger;
    }

    [Function("Greet")]
    public IActionResult Run(
        [HttpTrigger(AuthorizationLevel.Function, "get")] HttpRequest req,
        string name)
    {
        _logger.LogInformation("Greet function triggered for {Name}", name);

        return new OkObjectResult(new { message = $"Hello, {name}" });
    }
}

This looks and behaves like a standard ASP.NET Core controller action, which is deliberate. Isolated Process functions get the benefits of the full .NET runtime without the In-Process constraints.

Advantages Over a Standard Deployed API

No standing compute cost

On the Consumption plan, you pay only when a function executes. An API that handles 10,000 requests a day has a very different cost profile from one that handles 1,000,000.

For low-to-medium volume endpoints, especially internal or asynchronous ones, the serverless billing model can reduce spending significantly compared to a reserved plan.

Automatic scaling

Consumption and Flex Consumption plans scale automatically based on incoming load. You do not configure instance counts or autoscale rules.

Low operational overhead

No containers to build, no cluster to manage, no ingress to configure. For teams who want to focus on logic rather than infrastructure, Azure Functions HTTP is a leaner starting point.

Rapid deployment

A function can go from code to a live HTTP endpoint very quickly, with no additional platform setup required.

Disadvantages vs a Standard Deployed API

Cold starts

On Consumption plans, idle instances are released. When a request arrives on a cold instance, there is a startup delay before the response arrives.

For user-facing endpoints where sub-100ms latency is important, cold starts are a problem. Mitigations exist - pre-warmed instances, Flex Consumption minimum replicas, Premium plan - but they add cost and complexity.

Execution duration limits

Consumption plan functions have a default timeout of 5 minutes (configurable to 10). Premium and Dedicated plans extend this, but the execution model is still fundamentally different from a long-lived process.

Long-running, stateful operations do not fit well in standard HTTP functions.

Limited runtime control

Because Azure manages the host process lifecycle, you have less control over:

  • graceful shutdown timing
  • custom background services behavior
  • low-level network configuration

For most HTTP scenarios this does not matter. For specialised workloads it can.

Debugging complexity

Local development with func start is good but not identical to production. Distributed tracing, dependency injection, and middleware behavior can sometimes behave differently locally.

Vendor-managed concurrency

The Functions runtime makes scaling decisions. In very high concurrency scenarios, tuning behavior is limited compared to a full platform like AKS or Container Apps.

Cost Comparison

On the Consumption plan:

  • first 1 million executions per month are free
  • after that, billed per execution and per GB-second of execution time
  • no cost for idle time

On a Standard App Service plan:

  • billed by the hour regardless of traffic
  • predictable cost but no idle savings

The Consumption plan is significantly cheaper for infrequent workloads. For high-frequency, low-latency APIs, a reserved plan or Flex Consumption can be cheaper and more predictable.

Always model the expected call volume, average duration, and memory usage before assuming serverless is cheaper.

When to Use Azure Functions HTTP

Good fits:

  • internal automation endpoints called infrequently
  • webhook receivers for third-party integrations
  • lightweight data transformation endpoints
  • background-triggered HTTP callbacks
  • rapid prototyping of API behavior
  • endpoints that are part of a wider event-driven architecture

When NOT to Use Azure Functions HTTP

Poor fits:

  • high-throughput public APIs where cold start latency is unacceptable
  • APIs with strict sub-100ms P99 latency requirements
  • long-running operations that exceed execution duration limits
  • scenarios requiring deep runtime control or custom hosting behavior
  • workloads that are better served by a stateful or streaming model

If your endpoint needs to be fast, always-on, and highly tuned, a Container App or App Service is almost always the better choice.

Security Considerations

  • prefer AuthorizationLevel.Function or higher for non-public endpoints
  • use managed identity for Azure service access inside functions
  • avoid storing secrets in environment variables; prefer Key Vault references
  • validate request inputs at the function boundary

Summary

Azure Functions HTTP triggers are a strong choice when invocation volume is low-to-medium, cold starts are tolerable, and operational simplicity matters more than raw runtime control.

They are the wrong choice when you need always-on latency guarantees, fine-grained concurrency control, or advanced hosting behavior that the serverless execution model cannot deliver.

For all new .NET functions, use Isolated Process. It aligns with the .NET release cadence, supports full DI and middleware patterns, and is the only supported model going forward.

The clearest decision signal is usage pattern: if the endpoint is called rarely or unpredictably, serverless HTTP is a strong default. If it is called constantly and latency is critical, deploy a proper API.

References