Azure resource management

How to find empty App Service plans in Azure

Find App Service plans with no apps with Azure PowerShell and Resource Graph, run the query in Resource Graph Explorer, or run Altivane's Azure Unused Resources report for a workbook.

By the Published

To find empty App Service plans in Azure, query Azure Resource Graph for plans whose numberOfSites, the number of apps assigned to the plan, is 0. A plan on a dedicated tier, Basic or above, is charged for each of its instances whether or not any app runs on it, so an empty one costs money and serves nothing.

Choose the method that fits the job
MethodBest fit
PowerShellA CSV of empty plans across your enabled subscriptions, with each plan's SKU and tier.
Admin centreA quick query in Resource Graph Explorer, with nothing to install.
AltivaneRecommended for monthly cost reviews, with empty plans beside the other unused resources in 1 workbook.

Before you start

Use an account with read access to the subscriptions, such as the Reader role: Resource Graph returns nothing for resources you can't read. Microsoft lists no licence for Resource Graph, and it indexes changes with a short delay, so an app moved off a plan a moment ago can still be counted.

Know what an empty plan means. On the dedicated tiers each instance of the plan is charged, so the cost follows the plan's size and instance count, not its apps. Empty plans build up during development and when apps move between plans, but one can also be kept on purpose, so check with its owner before you remove it. The examples read and export; they don't delete or scale any plan. The script's finally block disconnects the account and clears its saved Azure contexts.

Option 1

Find empty App Service plans with PowerShell

Install the modules once. The script queries Resource Graph across the enabled subscriptions, follows every page of results, and saves each plan with no apps.

PowerShell
Install-Module -Name Az.Accounts, Az.ResourceGraph -Repository PSGallery -Scope CurrentUser
PowerShell
$ErrorActionPreference = 'Stop'
Connect-AzAccount -ErrorAction Stop
try {
    $subscriptionIds = @(
        Get-AzSubscription | Where-Object State -eq 'Enabled' | Select-Object -ExpandProperty Id
    )
    if ($subscriptionIds.Count -eq 0) {
        Write-Output 'No enabled subscriptions are available to this account.'
        return
    }
    $query = @(
        'Resources'
        '| where type =~ "microsoft.web/serverfarms"'
        '| where toint(properties.numberOfSites) == 0'
        '| project id, name, resourceGroup, subscriptionId, location,'
        'skuName = tostring(sku.name), skuTier = tostring(sku.tier)'
        '| order by id asc'
    ) -join ' '
    $rows = [System.Collections.Generic.List[object]]::new()
    $skipToken = $null
    do {
        $arguments = @{ Query = $query; Subscription = $subscriptionIds; First = 1000 }
        if ($skipToken) { $arguments.SkipToken = $skipToken }
        $page = Search-AzGraph @arguments
        foreach ($record in $page.Data) { $rows.Add($record) }
        $skipToken = $page.SkipToken
    } while ($skipToken)
    if ($rows.Count -eq 0) {
        Write-Output 'Every App Service plan in the enabled subscriptions has at least 1 app.'
    } else {
        $rows | Sort-Object skuTier, name |
            Select-Object name, skuName, skuTier, resourceGroup, subscriptionId, location, id |
            Export-Csv -Path './empty-app-service-plans.csv' -NoTypeInformation -Encoding utf8
        Write-Output "$($rows.Count) empty plans saved to empty-app-service-plans.csv."
    }
} finally {
    Disconnect-AzAccount | Out-Null
}

The CSV holds each empty plan's name, SKU, tier, resource group, subscription, location and resource ID. To leave out Free plans, which carry no charge, add '| where sku.tier !~ "Free"' before the project line, as Microsoft's own cost query does. Resource Graph paging needs id in the results, so keep it if you edit the query.

Option 2

Query empty plans in Resource Graph Explorer

  1. Sign in to the Azure portal with an account that can read the subscriptions.
  2. Search for Resource Graph Explorer and open it.
  3. Paste this query in Query 1 and choose Run query:
    KQL
    Resources
    | where type =~ 'microsoft.web/serverfarms'
    | where toint(properties.numberOfSites) == 0
    | project name, skuName = tostring(sku.name), skuTier = tostring(sku.tier),
        resourceGroup, subscriptionId, location
  4. Read the plans in Results, or choose Download as CSV for a file.

Explorer suits an occasional check with nothing to install. Open a plan from the results to see it in the portal before you decide anything. For the same list each month beside the other unused resources, use Altivane.

Common questions

Does an empty Free plan cost anything?

No. Microsoft names Free as the 1 tier with no charge for its compute, so an empty Free plan is clutter rather than cost. Leave Free plans out of the query if you only want savings.

Why does a plan with no apps still show CPU and memory use?

App Service runs its own system processes on a plan even when it holds no apps, for platform work such as security updates and monitoring. That use is normal and is no sign that an app is still there.

Where can I find other unused Azure resources?

The same Altivane report lists them, and each has a guide of its own. See how to find empty resource groups in Azure.

Microsoft references

Technical references checked on 7 November 2026. The example scripts have been reviewed and syntax checked; they have not been run against a live tenant.

Talk to us about Altivane

Questions, or pricing? Get in touch.

Contact us