How to Catch Azure Bicep Cost Changes in GitHub Pull Requests

By ResourcePulse Team · · 7 min read

Most Azure cost surprises start as a quiet pull request.

Someone bumps a SKU. Someone flips a parameter. Someone adds a small networking resource that bills by the hour. The diff looks tame. Reviewers approve. Two weeks later finance asks why the bill grew.

You can stop most of these incidents at PR time. You just need a workflow that surfaces cost the moment Bicep changes land in GitHub.

This post walks through that workflow.

Why GitHub is the right place to catch cost

Azure Cost Management tells you what already happened. Budgets and alerts fire after deploys. By then the resource exists, the bill clock is running, and rolling it back means another change request.

Pull requests are different. The code is still a proposal. Reviewers are already there. CI is already running. Adding a cost signal to that surface costs you nothing in tooling friction and saves you the awkward conversation later.

So the goal is simple. Every Bicep PR should answer three questions before it merges.

  1. What did this change cost relative to the previous state?
  2. Did anything cross a policy line your team cares about?
  3. Are the assumptions behind that estimate written down?

The four cost signals that matter in a Bicep diff

Before you wire up tooling, know what you are looking for. These four signals catch the majority of expensive PRs.

1. SKU changes

Azure SKU names look like model numbers. They tell you nothing about price unless you have memorized the catalog. A jump from Standard to Premium on App Service, or from GeneralPurpose to BusinessCritical on SQL, can multiply monthly cost by three or more.

Watch for these properties in a diff.

  • sku.name and sku.tier on any resource
  • properties.sku on storage and SQL
  • properties.hardwareProfile.vmSize on virtual machines
  • kind on App Service plans (Linux v2, Windows, Functions Premium)

2. Capacity and instance count

Capacity changes are sneaky because the SKU stays the same. Going from two instances to four doubles compute cost on that resource.

Look at:

  • sku.capacity on App Service plans
  • properties.autoscaleSettings.profiles[].capacity.minimum
  • properties.replicaCount on Container Apps
  • properties.numberOfWorkers on Functions

3. Resources that bill by the hour at zero traffic

Some Azure resources charge a flat hourly rate even when nothing is using them. Adding one in a Bicep file commits you to a monthly floor.

The usual suspects.

  • NAT Gateway (around $32 per month plus data processing)
  • Azure Firewall Standard (around $900 per month)
  • Application Gateway WAF v2 (around $250 per month minimum)
  • VPN Gateway and ExpressRoute Gateway
  • Azure Bastion
  • Premium tier Service Bus and Event Hubs

If a PR adds any of these to a non production environment without a guard, that is a finding worth blocking on.

4. Environment and feature toggles

A boolean change in one parameter can cascade across many resources. Reviewers miss these because the diff looks like one line.

Common offenders.

  • environment = 'prod'
  • enableZoneRedundancy = true
  • enableWaf = true
  • alwaysOn: true
  • retentionInDays raised on Log Analytics or App Insights
  • geoRedundantBackup = 'Enabled' on databases

Three ways to wire cost into a GitHub PR

Now the workflow piece. You have three options, ordered by effort.

Option A. Manual checklist in the PR template

The cheapest version. Add a section to your .github/pull_request_template.md that forces the author to fill in cost impact before requesting review.

## Cost impact

* SKUs changed: yes / no. List them.
* Capacity changed: yes / no.
* New always on resources: yes / no.
* Estimated monthly delta: $___
* Environment scope: dev / staging / prod

This works if your team is small and disciplined. It fails the moment someone is in a hurry, which is when the expensive PRs land.

Option B. Bicep what if plus a manual cost lookup

az deployment group what-if shows you the resource graph that will exist after deploy. You can run it in CI against a sandbox subscription and post the output as a PR comment.

This catches structural changes well. It does not estimate cost. You still need to look up SKUs in the Azure pricing calculator, which means the cost step is human and slow.

Useful as a foundation. Not enough on its own.

Option C. An assistant that posts cost and policy findings as a PR comment

The version that scales. A GitHub Action runs on every Bicep PR, parses the changed templates, looks up retail pricing for the SKUs, and posts a single comment with.

  • Estimated monthly cost for the new state
  • Delta against the previous state on the same branch
  • Policy findings (always on resources, missing tags, region pinning, SKU allowlists)
  • A link back to the run for full detail

Reviewers see the cost signal next to the diff. The comment updates in place on each push, so the thread stays clean.

This is the workflow that actually changes behavior, because the friction sits in the right place. Authors see the number before they request review. Reviewers see the number before they approve.

What ResourcePulse does in this workflow

ResourcePulse is the assistant version of Option C, focused on Azure Bicep and ARM. You drop the Action into your workflow, point it at a folder of templates, and it posts a single comment per PR with cost estimates, policy findings, and SKU suggestions.

It uses live Azure retail pricing, so the numbers track what you will actually pay. The comment updates in place when you push new commits, so reviewers always see the current state, not stale output.

Resource names get sanitized before they leave your repo, so the assistant never sees production identifiers or secrets. The Preview tier is free for one repo. Starter at $29 per month covers small teams. Team at $79.99 covers organizations with multiple repos.

You can install it from the GitHub Marketplace or from resourcepulseapp.com.

A practical rollout plan

If you are starting from zero, here is the order that works.

  1. Add the cost section to your PR template this week. It costs nothing and surfaces the conversation.
  2. Add what-if to CI for one repo. Watch what reviewers actually look at.
  3. Pick one expensive resource type your team has been bitten by. Write a policy rule for it. Examples. No NAT Gateway in dev. No SQL Business Critical without an approved label. No App Service Premium v3 outside production.
  4. Add a cost assistant to the same repo. Let it run for a week before you tune any rules.
  5. Roll out to the rest of your repos once the signal feels right.

Most teams over engineer step three and skip step four. Do them in the other order. Generic cost signal first. Custom rules second, once you know what you actually care about.

What good looks like after a month

You can tell the workflow is working when three things happen.

Authors start writing the cost number into the PR description before anyone asks. Reviewers stop approving SKU changes without a justification comment. Finance stops being the first team to notice budget movement.

That last one is the real win. Cost stops being a quarterly cleanup project and starts being a normal part of code review, which is where it should have been all along.

If you want a five minute version of this workflow on one repo today, install ResourcePulse, point it at your Bicep folder, and open a test PR. The first comment you see is the workflow.