Azure Cost Optimisation in 2026: Practical Wins for Real-World M365 & Cloud Environments
[For IT Pros]
Budgets are getting tighter, but your Azure and M365 bills keep creeping up. Finance wants predictability, leadership wants new features, and you’re stuck explaining why the invoice jumped 18% last quarter.
This guide is how I approach cost optimisation in real environments: no fantasy greenfield, no “just refactor everything to serverless”. You’ll get concrete checks, scripts, and design decisions you can apply this week.
1. Start With Visibility, Not Random Savings
1.1 Build a Cost Ownership Model First
Before you shave pennies off VMs, make sure you know who owns what. If nobody owns it, nobody will care when it’s expensive.
Baseline approach I use in most orgs:
- Management groups: Split at least into
Corp,Prod,NonProd, plus any regulated units (e.g.Regulated). - Subscriptions: One per major business domain or environment, not per project you spin up for 3 months.
- Tags (enforced):
Owner,CostCenter,Environment,Application,BusinessUnit.
Use a policy initiative at the management group to make these tags mandatory on all cost-driving resources (VMs, disks, PaaS, databases, AKS, Storage).
// Example: Require CostCenter tag on VMs
resource policyDef 'Microsoft.Authorization/policyDefinitions@2023-04-01' = {
name: 'require-costcenter-tag-vm'
properties: {
displayName: 'Require CostCenter tag on virtual machines'
mode: 'Indexed'
policyRule: {
if: {
allOf: [
{ field: 'type', equals: 'Microsoft.Compute/virtualMachines' }
{ field: 'tags.CostCenter', exists: 'false' }
]
}
then: {
effect: 'modify'
details: {
roleDefinitionIds: [
'/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c'
]
operations: [
{
operation: 'add'
field: 'tags.CostCenter'
value: 'UNKNOWN'
}
]
}
}
}
}
}
Even defaulting to UNKNOWN is better than missing tags: it makes the “who owns this mystery workload?” conversation much easier.
1.2 Use Cost Views That Match How Your Org Thinks
In 2026, the Azure Portal cost views and Cost Management workbook templates are good, but most orgs still look at cost like this:
- By Business unit (Sales, Operations, R&D)
- By Product / Application
- By Environment (Prod vs NonProd)
Create three cost views or workbooks that mirror this, using the tags above. Export them monthly to Power BI or your finance system. Once people see their spend, optimisation conversations stop being theoretical.
2. Kill or Right-Size Before You “Optimise”
2.1 The 30-Day Zombie Hunt
You’ll get the quickest wins by deleting what shouldn’t exist. Run a 30-day campaign focused purely on unused or underused resources.
Use Azure Advisor and combine it with your own checks. Here’s a PowerShell pattern I use to find low-CPU VMs over the last 14 days:
Connect-AzAccount
$subscriptionId = '<SUBSCRIPTION_ID>'
Select-AzSubscription -SubscriptionId $subscriptionId
$start = (Get-Date).AddDays(-14)
$end = Get-Date
$vms = Get-AzVM -Status
$result = @()
foreach ($vm in $vms) {
$metric = Get-AzMetric -ResourceId $vm.Id `
-TimeGrain 1.00:00:00 `
-MetricName 'Percentage CPU' `
-StartTime $start -EndTime $end
$avgCpu = [math]::Round(($metric.Data.Average | Measure-Object -Average).Average, 2)
$result += [pscustomobject]@{
Name = $vm.Name
ResourceGroup = $vm.ResourceGroupName
Location = $vm.Location
PowerState = ($vm.Statuses | Where-Object Code -like 'PowerState/*').DisplayStatus
AvgCpu14Days = $avgCpu
}
}
$result | Where-Object { $_.AvgCpu14Days -lt 5 } `
| Sort-Object AvgCpu14Days `
| Export-Csv '.\low-util-vms.csv' -NoTypeInformationSend that CSV to app owners with a simple question: Can we shut this down, resize, or schedule off-hours?
2.2 Storage: The Silent Budget Drain
Storage costs don’t scream like a big premium VM, but they quietly stack up. Common 2026 issues I keep seeing:
- Premium SSDs still attached to deallocated VMs “just in case”.
- Gigabytes of log files in hot blob storage that nobody reads.
- Old database backups and snapshots with no retention policy.
Quick wins:
- Use lifecycle management rules on storage accounts: move logs to cool/archive after 30–90 days, and delete after a sensible period.
- Set default retention on diagnostic settings instead of leaving them “forever”.
- Run a monthly report of unattached disks and review/delete.
# Find unattached managed disks
Get-AzDisk | Where-Object { -not $_.ManagedBy } |
Select-Object Name, ResourceGroupName, Sku, DiskSizeGB, TimeCreated3. Design Patterns That Keep Costs Under Control
3.1 Separate Scaling for Compute and Data
A lot of environments are still running “fat” VMs because the app and data are glued together. 2026 best practice is boring but effective: separate compute and data so you can scale independently.
Patterns that consistently save money over time:
- Stateless app tier on VM Scale Sets, AKS, or Azure Container Apps with autoscale.
- Managed database (Azure SQL/ PostgreSQL Flexible Server) with right-sized tiers and auto-pause/scale where possible.
- Blob storage for files instead of big VM disks.
On AKS specifically, avoid the 2023 trap of “just one big node pool of Standard_D8s_v5”. Use at least:
- One baseline node pool for steady workloads.
- One spot or burst node pool for batch/low-priority jobs.
# Example: create an AKS cluster with a spot node pool for batch
az aks create \
--resource-group rg-aks-prod \
--name aks-prod-01 \
--node-count 3 \
--node-vm-size Standard_D4as_v5 \
--enable-cluster-autoscaler \
--min-count 3 --max-count 10 \
--nodepool-name system
az aks nodepool add \
--resource-group rg-aks-prod \
--cluster-name aks-prod-01 \
--name spotpool \
--priority Spot \
--eviction-policy Delete \
--spot-max-price -1 \
--node-vm-size Standard_D4as_v5 \
--node-count 0 \
--enable-cluster-autoscaler \
--min-count 0 --max-count 203.2 Use the Right PaaS Tier, Not Always the Cheapest
Teams often choose the lowest tier to “save money”, then over-provision because of performance issues, ending up more expensive than a balanced tier.
Two rules of thumb I use:
- If you’re consistently above 70% resource utilisation on a tier, move up one tier and reduce instance count.
- If you’re consistently below 20% utilisation, move down a tier or switch to a lower-commitment model (e.g. auto-scale / serverless where supported).
On Azure SQL: be honest about whether you need Business Critical. Many workloads sit fine on General Purpose with good indexing and query tuning. Use the automatic tuning features – they save both performance time and over-sizing cost.
4. Commitment Plans, Reservations & Licensing Tricks (Without Losing Flexibility)
4.1 Reservations & Savings Plans That Actually Make Sense
In 2026, Azure’s savings story is more complex: Reservations, Compute Savings Plans, and service-specific commitments. Treat them as capacity planning tools, not one-off discounts.
Approach I recommend:
- Only commit for steady-state workloads you expect to run for 12–36 months (core app servers, production databases, baseline AKS capacity).
- Use 1-year commitments for anything you’re not 95% sure about.
- Prefer shared scope reservations at the enrollment/management group level to avoid stranded discounts.
Use Cost Management’s “Reservation recommendations” and “Savings Plan recommendations” as input, not gospel. Cross-check with your roadmap: are you planning a migration, refactor, or move to a different region in the next 12–18 months?
4.2 M365 & Licensing: Don’t Pay Twice
I still see organisations paying for features twice: once in M365, once via third-party tools. Typical overlaps:
- Endpoint security: using a separate EDR when you already pay for Defender for Endpoint Plan 2.
- Cloud app security: third-party CASB plus Defender for Cloud Apps (now under Defender XDR stack).
- Backup/archiving: paying for separate tools while sitting on top-tier SharePoint/Exchange retention and backup features.
Run a licensing heatmap:
- List each M365 SKU (E3, E5, Business Premium, F3, etc.).
- For each, tick the features you actually use today.
- Highlight overlaps with other paid tools.
Then decide: either lean into the Microsoft stack and drop redundant tools, or strip back to cheaper M365 SKUs and keep your best-of-breed tooling. Both are valid; paying double is not.
5. Automation: Guardrails That Keep Costs Down Automatically
5.1 Auto-Shutdown & Schedules for Non-Prod
Dev, test and training environments are classic cost leaks. By 2026, there’s no excuse for them running 24/7 unless they truly need to.
Patterns that work:
- Use the built-in auto-shutdown for dev/test VMs where possible.
- For anything more complex, use Azure Automation, Logic Apps, or functions to implement schedules driven by tags.
# Example: Stop all non-prod VMs with a specific tag after 8pm
Connect-AzAccount
$subscriptionId = '<SUBSCRIPTION_ID>'
Select-AzSubscription -SubscriptionId $subscriptionId
$now = Get-Date
if ($now.Hour -ge 20 -or $now.Hour -lt 7) {
$vms = Get-AzVM -Status | Where-Object {
$_.Tags.Environment -eq 'NonProd' -and
$_.Tags.AutoSchedule -eq 'Enabled' -and
($_.Statuses | Where-Object Code -like 'PowerState/running')
}
foreach ($vm in $vms) {
Write-Output "Stopping VM: $($vm.Name) in RG: $($vm.ResourceGroupName)"
Stop-AzVM -Name $vm.Name -ResourceGroupName $vm.ResourceGroupName -Force
}
}Run that as an Automation account runbook or a scheduled GitHub Action using OpenID Connect auth to your subscription.
5.2 Budget Alerts That People Actually Read
Most orgs have some budget alerts configured, but they either go to a shared mailbox nobody checks or spam an entire team.
Make alerts actionable:
- Create per-application or per-cost-center budget alerts using tags.
- Send alerts to Teams channels or specific distribution lists with the product owner included.
- Include a link to a cost workbook view filtered for that app so they can drill in immediately.
You want the message to be: “Your app is trending 25% above budget this month. Here’s the breakdown by resource type and environment.” Not “Your subscription is expensive, good luck.”
6. A 30-Day Action Plan You Can Start This Week
If you’ve read this far, you probably don’t need another generic conclusion. Here’s a concrete 30-day plan instead:
- Week 1 – Visibility
- Enforce the core tags (
Owner,CostCenter,Environment,Application) using policy. - Build three cost views: by Business Unit, by Application, by Environment.
- Enforce the core tags (
- Week 2 – Quick Wins
- Run the “zombie VM” and unattached disk scripts and challenge owners.
- Configure lifecycle management on all log-heavy storage accounts.
- Week 3 – Design & Commitments
- Identify 3–5 core workloads for right-sizing and potential reservations/savings plans.
- Review AKS/VM/app service scaling models and apply at least one change (autoscale, spot pool, or tier adjustment).
- Week 4 – Guardrails
- Implement non-prod shutdown schedules based on tags.
- Set up budget alerts for the top 5 cost-driving applications, routed to the right people.
If you do nothing else, get the tagging, cost views, and shutdown schedules in place. Those three alone usually shave 15–25% off without a single architectural rewrite, and they make every future optimisation conversation a lot easier.