Azure Functions Cost Optimisation: Pick the Right Plan

Azure Functions billing depends heavily on your plan. Here's how to pick the right one and tune memory, duration, and cold starts without overspending.

By Andrii Votiakov on 2026-02-08

Azure Functions cost surprises usually come from one of two directions: a team on the Consumption plan hitting unexpected scale, or a team on Premium plan paying for always-on workers for a workload that barely runs. Picking the wrong plan is the most expensive mistake, and it's fixable without rewriting anything.

Quick answer

Azure Functions has four hosting plans, each with different billing. Consumption is cheapest for low/spiky traffic but charges for every execution. Flex Consumption (GA in late 2024) gives you per-instance concurrency control and on-demand scaling with lower cold-start costs. Premium pre-warms instances but costs $130-400+/month even with zero traffic. App Service is only worth it if you're already paying for that plan. Match your plan to your traffic pattern — it's the biggest lever available.

The four plans and when each makes sense

Plan Billing model Cold starts Min cost/month Best for
Consumption Per execution + GB-seconds Yes (mitigated) ~$0 Event-driven, spiky, low-frequency
Flex Consumption Per execution + concurrency Lower ~$0 High-concurrency, need predictable scaling
Premium Per-second (pre-warmed workers) None ~$130 Latency-sensitive, VNet integration needed
App Service Flat (shared with other apps) None Existing ASP cost Already have idle ASP capacity

Most teams I review are on the wrong plan for their workload.

Consumption plan: tuning what you can control

On Consumption, you pay $0.000016/GB-second and $0.20/million executions. The free tier is 1 million executions and 400,000 GB-seconds/month — generous enough that simple workloads cost nothing.

The levers on Consumption:

Memory allocation. Functions on Consumption scale memory with execution size, but you can cap it via host.json or per-function settings. A function processing a 5 KB JSON payload doesn't need 1,500 MB. Profile the actual footprint; I commonly find Node.js functions allocated 400-600 MB doing work that needs 150-200 MB.

Execution duration. Default timeout is 5 minutes on Consumption (10 minutes is the max). If your function regularly runs 4 minutes and could run 90 seconds with better batching, that's a 2.6x reduction in GB-seconds. Look at your average duration in Application Insights before assuming it's fast.

Batch event sources. For Service Bus, Storage Queue, and Event Hub triggers, increase batch size. A function triggered once per message is doing 10x the invocations for the same throughput. Set maxMessageCount (Service Bus) or maxBatchSize (Event Hub) to process 10-100 messages per invocation.

Turn off DEBUG logging in production. Application Insights ingestion costs $2.76/GB. A verbose function writing 200 bytes per invocation × 10M invocations/day = 2 GB/day = $165/month in Insights alone. Set log level to Warning or Error for hot paths.

Flex Consumption: the new middle ground

Flex Consumption is worth knowing about if you're on Consumption and hitting either of these problems: cold starts that hurt user experience, or concurrency that scales in unexpected ways.

Flex gives you instanceMemoryMB (512 MB, 2048 MB, or 4096 MB) and a maximumInstanceCount cap. You choose how much concurrency runs per instance. This makes scaling more predictable than Consumption's automatic approach.

Billing is similar to Consumption but the instance granularity is different. For workloads with medium-consistent traffic, Flex often comes out 20-35% cheaper than Premium because you're not paying for permanently warm workers.

The practical migration from Consumption to Flex is straightforward: change the functionAppConfig SKU in your ARM template or Bicep, keep the same function code, and reconfigure host.json concurrency settings.

Premium plan: when it's justified and when it isn't

Premium pre-warms instances so cold starts don't happen. You pay per-second for at least one pre-warmed worker, always. That's roughly $130-150/month for a single EP1 (1 core, 3.5 GB) worker doing nothing.

Premium is worth it when all three conditions are true:

  1. You need guaranteed sub-second P99 response times
  2. Consumption cold starts (200-500ms for .NET, 500-1500ms for Java) are unacceptable
  3. VNet integration is required (private endpoints to databases, private APIs)

Premium is not worth it for:

  • Background processors, batch jobs, cron triggers
  • Any function called less than a few thousand times per day
  • Dev and staging environments

I see teams running 3-4 Premium plan function apps for workloads that could run on Consumption or Flex for under $20/month total. The usual story: someone enabled Premium because of a cold-start complaint on one latency-sensitive endpoint, and everything got moved to the same plan.

Fix: move the one latency-sensitive function to Premium or use Always Ready instances (a Flex Consumption feature). Move everything else back to Consumption or Flex.

Always Ready instances vs Provisioned Concurrency

Flex Consumption has "Always Ready" instances that stay warm for specific functions. You pay $0.60-1.20/month per always-ready instance per function. Compare that to Premium's $130+/month for the whole plan.

If you need warm instances for two latency-sensitive functions and can tolerate cold starts for the rest, Always Ready on Flex saves you ~$120/month vs Premium, per function app.

ARM (Graviton) on Azure Functions

Azure Functions support ARM64-based App Service plans and Premium plans via the linuxFxVersion setting. ARM-based Premium workers cost approximately 20% less than x86 equivalents.

For Consumption and Flex, billing is the same regardless of architecture — Azure handles the underlying hardware. ARM mostly matters on Premium where you're paying for the worker regardless of utilisation.

Cold starts: cheap fixes first

Cold starts are often why teams upgrade to Premium. Before paying $130+/month, try:

Strip package size. A .NET 8 function app with 80 MB of unused dependencies cold-starts 2-3x slower than a trimmed 15 MB app. Use dotnet publish --configuration Release --self-contained false and examine what's in your deployment package.

Use .NET 8 Isolated worker model. In-process (legacy) has longer cold starts. Isolated worker model is faster and required for .NET 9+.

Pre-compiled Python. Python Functions cold-start slowly with large dependency trees. Pre-compile with pip install --target and ship the compiled packages.

HTTP keep-alive tricks. A simple pinger (another free-tier Function, Logic App, or external cron) calling your endpoint every 5 minutes keeps the instance warm on Consumption. Not elegant, but costs nothing and eliminates cold starts for most scenarios.

Realistic numbers

A recent client spending ~$1,400/month on Azure Functions:

Action Monthly saving
Move 6 non-latency-critical apps from Premium to Flex Consumption $780
Reduce memory allocation across 12 functions (avg 3x over-provisioned) $210
Increase Service Bus batch size from 1 to 50 messages $180
Set Application Insights to Warning log level on 4 hot paths $145

Final bill: $85/month, 94% reduction. The Premium-to-Flex migration alone accounted for more than half the savings.


If you're comparing Azure Functions against Lambda or Cloud Run, see Cloud Run vs Lambda vs Azure Functions for a full cost comparison across all three platforms.

If your Azure Functions bill is higher than expected and you're not sure which plan or settings to change, book a call. I'll review your plan selection, function execution metrics, and Application Insights spend in one session.