Skip to main content
idle · azure

App Service plans with zero apps that still bill for their VM instances

resource types
1
rule IDs covered
1
severity
medium

What does ZopNight detect here?

ZopNight flags an Azure App Service plan whose `numberOfSites` is 0, meaning no web app, API or function app is assigned to it, unless `CpuPercentage` reached 5% in the last 30 days. Microsoft states that a plan with all its apps deleted keeps accruing charges for its tier and instance count, so the empty plan is the whole saving.

Signal and threshold

How ZopNight evaluates App Service plans with zero apps that still bill for their VM instances.
Field Value
Rule IDsRC-222
Categoryidle
Severitymedium
MetricCpuPercentage (activity guard)
ThresholdnumberOfSites = 0, CPU below 5%
Evaluation window30d
SourceZopNight
Permissions usedMicrosoft.Web/serverfarms/Read · Microsoft.Insights/Metrics/Read

An App Service plan bills for instances, not for apps

In App Service, the plan is the compute. On the Basic, Standard and Premium tiers, Microsoft’s hosting plan overview says the plan defines the number of VM instances and each instance is charged; only the Free tier carries no charge. The apps on it do not add to that price.

Take the apps away and nothing changes. The cost planning guide says it plainly: when you delete all apps in a plan, the plan continues to accrue charges based on its pricing tier and number of instances, and you should delete it or scale it down to Free.

Listing empty plans

Terminal window
az appservice plan list \
--query "[?numberOfSites==\`0\`].{name:name, rg:resourceGroup, sku:sku.name, workers:sku.capacity}" \
-o table

numberOfSites is the number of apps assigned to the plan, as reported by the App Service API.

What ZopNight checks before flagging an empty plan

  1. The plan’s app count, read from Azure Resource Graph, is exactly 0.
  2. The plan shows no recent activity: when at least 30 days of CpuPercentage data exist, both the average and the peak must be below 5%. CPU at or above that level suggests something is still running on the instances, so ZopNight holds off.
  3. The plan has a known monthly cost above zero.

Plans that are not reported

If the app count could not be read, there is no finding; an unknown is not treated as zero. Plans with any app assigned are out of scope here. A plan that hosts apps but is larger than they need is a sizing question, handled by Azure App Service Plan Right-Sizing. Free-tier plans have no cost to recover and do not appear.

Saving is the plan’s fixed monthly fee

Terminal window
saving = current monthly cost of the plan (tier rate x instance count)
cost after fix = 0

Removing or reusing an empty plan

  1. Confirm no deployment pipeline expects to create apps on this plan by name.
  2. If apps elsewhere could use it, move them onto this plan and delete their old, emptier plans instead; that keeps one plan billing rather than two.
  3. Otherwise delete it: az appservice plan delete --resource-group my-rg --name my-plan --yes.
  4. If you want to keep the plan for later, scale it to Free with az appservice plan update --resource-group my-rg --name my-plan --sku FREE, where the tier and operating system allow it.

See it fire on your bill.

Connect an account read-only. The first findings land in minutes.

472 rule families across 353 resource types on 22 platforms. Every threshold, metric, and IAM action is documented on these pages before you grant anything.

472 rule families documented
353 resource types covered
read-only default access level
Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001· 20–60% off the bill, first month· 4 platforms · 1 console· Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001· 20–60% off the bill, first month· 4 platforms · 1 console·