Skip to main content
emnode
Cost

Right-size underutilised App Service plans

One capability across every web app, API and function host: make sure no App Service plan is paying for a SKU far larger than its workload actually uses, so the compute you buy matches the compute you run.

14 min·10 sections·AZURE

Last reviewed

Right-sizing App Service plans: the basics

What does an over-provisioned App Service plan actually look like?

An App Service plan is the unit you pay for: a fixed SKU running a fixed number of instances, billed by the hour whether the apps on it are busy or idle. The apps themselves are free in billing terms; the plan is the meter. Over-provisioning shows up in two shapes. The plan can be running a larger SKU than the load needs, a P2V3 sitting at single-digit CPU when a P1V3 or an S1 would carry the same traffic. Or it can be running more instances than the load needs, three workers where one would do. Either way you are paying for headroom that is never used.

Azure Advisor turns this into a single cost recommendation: 'Right-size underutilized App Service plans'. It analyses the CPU usage of each plan over the past seven days and, where utilisation is low, flags that you can often move to a less expensive SKU while keeping the same features. The recommendation carries Medium impact and targets the microsoft.web/sites resource type. It is one of a small family of App Service cost findings, alongside 'Unused/Empty App Service plan' for plans with no apps at all, and the App Service reserved-instance recommendation for steady plans you will keep.

Most of this over-spend is drift, not intent. A plan sized for a launch-day traffic spike that never recurred, an environment cloned from production at production scale, a Premium plan picked because someone needed one feature and took the whole tier with it. The work is to find every plan whose SKU and instance count run well ahead of its measured load, confirm the low utilisation is real rather than a quiet period before a known peak, and step each one down to the cheapest SKU that still carries the workload and keeps the features the apps depend on.

In this lesson you will learn how Azure bills App Service, how Advisor decides a plan is under-utilised, and how to step plans down to the right SKU without dropping traffic or losing a feature the apps depend on. You will see how to read the CPU evidence yourself, how to tell a genuinely idle plan from one that is quiet before a known peak, and how to bank the saving with a single command or a Bicep change.

Fun fact

The plan that outlived its launch

A surprising amount of cloud waste comes down to a single forgotten sizing decision. App Service plans are a classic example: a team sizes a plan for the busiest hour it can imagine on launch day, traffic settles into a fraction of that, and the SKU never moves because nothing breaks and nobody is paid to notice. Azure Advisor exists precisely because this pattern is so common that Microsoft built a service to watch your CPU for you and point at the plans sitting idle. The saving is often hiding in plain sight on the bill: the same plan, the same apps, a smaller SKU, and a line item that drops the moment you resize.

Finding under-utilised plans across a subscription

Priya runs the platform team at a SaaS company whose Azure bill has crept up quarter on quarter without a matching jump in traffic. App Service is one of the larger lines, and Advisor is showing a cluster of 'Right-size underutilized App Service plans' findings across both the production and staging subscriptions.

Rather than trust the headline saving blindly, Priya starts by listing every plan with its SKU and instance count, so the obviously over-sized plans are visible before anyone reads a single CPU chart.

Start by listing every App Service plan with its SKU tier, size and worker count. This is the inventory the Advisor findings sit on top of.

$ az appservice plan list --query "[].{name:name, tier:sku.tier, size:sku.name, workers:sku.capacity}" -o table
Name Tier Size Workers
---------------- ---------- ------ -------
api-prod-plan PremiumV3 P2V3 3
web-prod-plan PremiumV3 P1V3 2
web-staging-plan PremiumV3 P1V3 1
# api-prod-plan is a P2V3 running 3 workers. Check its CPU before assuming it needs them.

A large SKU running several workers is the highest-value candidate. The next step is to confirm the CPU is genuinely low, not to resize on sight.

How Advisor decides an App Service plan is under-utiliseddeep dive

The recommendation rests on one signal: CPU. Advisor analyses each plan's CPU usage over the past seven days and, where it stays low, concludes the plan can often move to a less expensive SKU while keeping the same features. You can read the same evidence yourself with Azure Monitor: the CpuPercentage metric on the plan's Microsoft.Web/serverfarms resource is the number Advisor is watching, and pulling the seven-day trend tells you whether the low utilisation is steady or just a quiet window. CPU is the headline signal, so before you resize, sanity-check memory and any other constraint the apps actually hit, since a plan can be CPU-idle but memory-bound.

Two properties on the plan describe its cost. The SKU name, such as P1V3 or S1, sets the machine size and the hourly rate; stepping it down is scaling up or down. The capacity, the number of workers, sets how many instances run in parallel; stepping it down is scaling out or in. A plan can be over-provisioned on either axis, and Advisor's CPU view will point at whichever one is carrying unused headroom. The fix is to bring the SKU and worker count back in line with the measured load.

Advisor refreshes on its own cadence rather than the instant you resize, so a finding does not clear the moment you act; the control-plane change is immediate but the recommendation catches up on the next assessment. The durable position is not to chase the findings to zero once, but to wire Advisor's App Service cost view into a standing review so new over-provisioning is caught as it appears, and to reach for autoscale on the genuinely spiky plans so they buy peak capacity only when the peak is real.

What is the impact of leaving plans over-sized?

The direct impact is money billed every hour for compute that is never used. An App Service plan one SKU larger than its load is not a rounding error; it is a fixed hourly overcharge that compounds across every plan and every environment until someone resizes it. Staging and pre-production are the worst offenders, often cloned at production scale and then left running a heavyweight SKU around the clock to serve a trickle of test traffic.

The second-order impact is drift that hides. Because nothing breaks when a plan is over-sized, the waste is invisible in day-to-day operations and only shows up if someone reads the bill line by line or works the Advisor findings. Left alone, the gap between what you provision and what you use widens every time a plan is cloned, scaled up for a one-off event, or sized defensively, and the run rate climbs without anyone making a decision to spend more.

There is an upside risk too, in the other direction. Right-sizing is reversible in minutes, so the downside of a step-down that turns out slightly too tight is a quick scale-up, not an outage you cannot undo. That asymmetry, recurring saving on one side, fast and reversible adjustment on the other, is what makes leaving plans over-sized the more expensive mistake over any meaningful horizon.

How do you right-size plans safely?

Work the capability as one loop rather than chasing individual findings. The order matters: confirm the load is genuinely low before you resize, so you step a plan down on evidence rather than on a single quiet week.

1. Inventory every plan by SKU and worker count

List every App Service plan with its SKU tier, size and capacity. Treat this inventory as the source of truth alongside the Advisor findings, because the same plan can be over-provisioned on its SKU, on its worker count, or on both, and the list tells you which axis to look at first.

2. Confirm the low utilisation is real

For each flagged plan, read the seven-day CpuPercentage trend in Azure Monitor rather than resizing on the finding alone. Check it is steady low usage, not a quiet window before a known peak, and sanity-check memory in case the plan is CPU-idle but memory-bound. This is the step that separates a safe downsize from one that clips a real peak.

3. Step down to the right SKU or worker count

Move each genuinely over-sized plan to the cheapest SKU that carries the load and keeps the features the apps depend on, and trim the worker count where the headroom is in instances rather than machine size. Each change is a single command per plan and takes effect quickly. Start with the largest plans, where the per-hour saving is biggest.

4. Handle the spiky plans with autoscale, not headroom

A plan that idles most of the time but spikes on a schedule should not carry permanent headroom. Put it on a smaller base SKU with autoscale so it adds workers only when the load is real, and earmark the steady production plans you will keep for a reserved-instance or savings-plan commitment to lock in a further discount. Codify the right size in Bicep so a redeploy cannot silently restore the oversized SKU.

# 1. List the Advisor cost findings so you act on measured under-utilisation.
az advisor recommendation list --category Cost \
  --query "[?contains(shortDescription.problem, 'App Service')].{resource:impactedValue, problem:shortDescription.problem}" \
  -o table

# 2. Read the 7-day CPU trend Advisor is watching, before you resize.
az monitor metrics list \
  --resource "/subscriptions/<sub-id>/resourceGroups/<rg>/providers/Microsoft.Web/serverfarms/api-prod-plan" \
  --metric CpuPercentage \
  --aggregation Average \
  --interval PT1H \
  --start-time 2026-06-10T00:00:00Z \
  --end-time 2026-06-17T00:00:00Z \
  -o table

# 3. Step the plan down once the CPU confirms the headroom is unused.
#    --sku changes the machine size (scale up/down).
az appservice plan update \
  --name api-prod-plan \
  --resource-group api-prod-rg \
  --sku P1V3

# 4. Optionally trim the worker count where the spare capacity is in instances.
#    --number-of-workers changes how many instances run (scale out/in).
az appservice plan update \
  --name api-prod-plan \
  --resource-group api-prod-rg \
  --number-of-workers 2

Quick quiz

Question 1 of 5

Azure Advisor flags 'Right-size underutilized App Service plans' across several plans. What signal is the recommendation based on, and over what window?

You can now treat App Service right-sizing as one recurring capability rather than a scatter of findings: inventory every plan by SKU and worker count, confirm the low CPU is real before you resize, step the over-sized plans down to the cheapest SKU that carries the load, and handle the spiky ones with autoscale instead of permanent headroom. Wire Advisor's App Service cost view into a standing review and codify the right size in Bicep so the saving sticks.

Back to the library