Bicep PR Review Checklist That Actually Catches Expensive Mistakes
By ResourcePulse Team · · 4 min read
It was one of those PRs you approve on autopilot.
A couple of lines changed in a Bicep file. No new resources. No scary networking blocks. Just a "cleanup" of parameters and a small SKU tweak that looked... harmless.
Reviewed. Approved. Shipped.
Then a week later: finance pings the team.
"Why did cloud costs jump?"
The blast radius wasn't obvious because the diff didn't look like money. It looked like "engineering."
And that's the trap.
In Infrastructure-as-Code, cost isn't a line item -- it's an emergent property:
- a default you didn't notice,
- a parameter flip that silently moved the deployment into "production mode,"
- an "always-on" resource someone added because it's "best practice."
So when reviewers miss expensive changes, it's usually not because they're careless.
It's because diffs hide cost.
Why cost isn't visible in diffs
Most PR diffs show what changed, not what it means operationally.
Common reasons expensive changes slip through:
-
SKUs are codewords, not prices "Standard" vs "Premium", "v2", "WAF", "BusinessCritical"... none of that screams "hundreds/day," but it often is.
-
Bicep defaults are invisible unless you know them If a property is omitted, the platform picks a default -- sometimes cheap, sometimes not, sometimes "depends."
-
Parameters hide intent One param flip can enable prod-grade features everywhere (zones, redundancy, higher tiers, autoscale minimums).
-
Always-on resources don't look dangerous NAT Gateway, Firewalls, VPN/ExpressRoute Gateways, Application Gateway -- these quietly charge every hour.
-
Networking has "premium traps" It's easy to accidentally add a component that's always on, billed hourly + data processed.
So you need a review process that forces cost awareness, even when the PR looks tiny.
The checklist
1) Compute SKU changes (translate "names" into impact)
When you see a SKU, force a quick classification:
- Is it a tier jump? (Basic -> Standard -> Premium)
- Is it a "v2 / WAF / BusinessCritical / Zone-redundant" jump?
- Is it a "minimum instance count" change? (
autoscale minCapacity,App Service sku.capacity, etc.)
Reviewer move -- if SKU changed, ask for:
- what it costs relative to previous SKU (ballpark),
- why it's needed now,
- whether it's scoped to prod only.
2) "Always-on" resources (the silent invoice)
These are the classic "you'll pay even at 0 traffic" resources:
- NAT Gateway
- Azure Firewall
- Application Gateway (especially WAF_v2)
- VPN Gateway / ExpressRoute Gateway
- Bastion
- Premium load balancing patterns
- SQL / managed databases scaled up "just in case"
Reviewer move -- any addition here requires a justification and an environment scope (prod-only vs dev).
3) Dev/prod parameter flips (the sneakiest ones)
Look for changes like:
environment = 'prod'enableZoneRedundancy = trueenableWaf = truelogAnalyticsRetentionDays = 90minCapacity: 2 -> 3alwaysOn: false -> true
Reviewer move -- if a param flips, check:
- where it's used,
- whether it impacts multiple resources,
- whether it's gated by environment.
4) Networking premium traps (NAT, firewall, gateways)
Networking changes deserve paranoia because they can introduce hourly billing + data processing costs.
Red-flag patterns:
- NAT Gateway added "for outbound reliability"
- Firewall added "for compliance"
- App Gateway/WAF added "for security"
- Private endpoints + DNS zones proliferate across services
Reviewer move -- when networking changes appear, explicitly ask:
- what problem it solves,
- whether a cheaper alternative exists for dev/test,
- what the expected baseline monthly cost is.
5) Red flags section (fast scanning heuristics)
If you're skimming a PR, search for these strings:
Costly keywords
Premium,Standard_v2,WAF,v2,BusinessCriticalzoneRedundant,availabilityZones,zonesminCapacity,capacity,autoscaleFirewall,NatGateway,ApplicationGateway,VpnGateway,BastionretentionInDays,diagnosticSettings
Reviewer rule -- if any red-flag keyword shows up, the PR needs a cost comment before approval.
The checklist (copy-paste):
[ ] Any SKU changed? (tier, v2, WAF, BusinessCritical, Premium)
[ ] Any capacity/minimum instances changed?
[ ] Always-on resource added? (NAT Gateway, Firewall, App Gateway, Bastion)
[ ] Justification + env scope (prod-only vs dev)
[ ] Any env/param flip? (dev -> prod, zone redundancy, WAF toggle)
[ ] Does the param affect multiple resources?
[ ] Baseline cost estimate included? (rough, order of magnitude)
PR template snippet (drop into your repo)
Put this into your PR template so the author does the homework before review.
- What SKUs changed?
- Any always-on resources added?
- Any dev/prod parameters flipped?
- Any networking "premium traps" introduced?
- Expected cost delta (rough)
Make the checklist the default, not the exception
A checklist only works when someone runs it. The honest problem with manual cost review is that the small PRs — the ones most likely to hide an expensive default — are exactly the ones reviewers skim.
So pick one of two paths. Either bake the checklist into your PR template so the author answers the cost questions before review, or automate the scan so the answers are already in the thread when the reviewer arrives.
ResourcePulse does the second. It reads the Bicep in a pull request and posts one comment with the cost delta and the same governance flags this checklist covers — SKU jumps, always-on resources, parameter flips, missing tags. It is free on one repo, so you can put it on a real project and see whether the comment changes how your team reviews. The checklist still does the human half; this just makes sure nothing reaches a reviewer uncounted.