The invoice arrives, it is roughly twice what it was, and the honest answer from everyone in the room is that they are not sure why. That is not incompetence. Cloud billing is genuinely hard to read, the charges that hurt are rarely the ones you were watching, and the person who can approve stopping the spend is almost never the person who started it.
Before anything else: do not start switching things off. The temptation is enormous and it is how a cost problem becomes an outage, which is far more expensive. Work through the five suspects below in order. They are ordered by how often they turn out to be guilty, and you can usually find the culprit in an afternoon without touching anything that is running.
Before you touch anything: read the cloud bill properly
- Get the detailed bill, not the summary. You want the breakdown by service, by region and by day. The daily view is the important one: it turns the bill doubled into the bill doubled on the 14th, which is a far easier question.
- Find the day it changed. A step change points at something somebody did. A steady climb points at something accumulating. Those are different problems with different answers, and knowing which you have saves hours.
- Check every region, not just the one you use. Resources left in a region nobody looks at are a classic, and they are invisible on a console that defaults elsewhere.
- Ask what changed around that date. A deployment, a new feature, a migration, someone testing something, a marketing campaign that worked. Ask before investigating, because someone usually knows and has not connected it to the bill.
Suspect 1: things nobody turned off
The most common cause by a comfortable margin, and the least interesting. Somebody spun something up for a test, a demo, a migration or a bad afternoon, and it is still running. It has been running for four months. Nobody remembers it exists because nobody is looking at a list of what exists.
What to look for: compute instances with almost no usage, whole environments that were meant to be temporary, storage volumes not attached to anything, reserved addresses pointing at nothing, load balancers with no traffic, database instances nobody connects to. Detached storage is the one people miss most, because it costs the same whether it is attached to a running machine or to nothing at all.
This is usually safe to clean up, with one rule: snapshot before you delete, and wait a fortnight before deleting the snapshot. Cheap insurance against the one that turned out to matter.
Suspect 2: moving data around
The charge that catches everyone, because it is not a thing you provisioned and so it is not a thing you think to look at. You pay for data leaving, and often for data crossing between regions or zones. Nothing appears on any list of resources, so it hides.
Typical causes: an application talking across regions when it did not need to, backups replicating somewhere far away, chatty services in different zones, large files served straight from storage instead of through a content network, or a busy interface making far more calls than anyone intended. Look for a transfer line that is large relative to the rest of the bill, then work out what is talking to what.
Suspect 3: everything sized for a peak that never comes
Somebody picked a size at the start, chose generously because nobody wants to be the person who under-provisioned, and nobody has revisited it since. Meanwhile the load has never come close.
Look at actual utilisation over a month, not at a busy hour. Machines sitting at single-digit processor use, databases provisioned for throughput they never approach, oversized capacity that was set once and forgotten. Right-sizing this is real money and it is genuinely safe when done gradually, with a look at the peaks rather than only the average, because averages hide the one hour a week that actually matters.
Suspect 4: storage that never expires
Storage is cheap enough that nobody manages it, which is exactly why it grows without limit. Every log, every backup, every snapshot, every uploaded file, kept forever because nobody ever decided otherwise.
The tell is a storage line that grows every month and never falls. Look for logs with no retention limit, snapshots going back years, old versions of every file where versioning was switched on and never bounded, and backups of systems that no longer exist. The fix is dull and permanent: set retention rules and lifecycle policies so old data moves to cheaper storage and then goes away on its own. Decide the retention with whoever is accountable for it, not with whoever happens to be in the console.
Suspect 5: something somebody changed
If the bill stepped up on a specific day, this is your answer, and the daily breakdown you pulled at the start has already pointed at it.
- A deployment that added a component, a queue, a cache or a scheduled job that runs far more often than intended.
- Logging turned up for a debugging session and never turned back down. Verbose logging is startlingly expensive at volume.
- Automatic scaling that scaled up correctly for a spike and never came back, or that is reacting to the wrong signal.
- A retry loop, where something fails and retries hard, and you pay for every attempt.
- A commitment or discount that lapsed, which changes nothing technically and changes the invoice a great deal.
- Genuine growth. More customers, more usage, more cost. Check this before you cut anything.
What is safe to switch off, and what is not
| Action | Risk | How to do it safely |
|---|---|---|
| Delete unattached storage volumes | Low | Snapshot first, wait a fortnight, then delete the snapshot. |
| Set retention on logs | Low | Agree the period with whoever is accountable, then apply it. |
| Delete old snapshots | Low to medium | Keep the most recent of each. Confirm nothing restores from them. |
| Right-size over-provisioned compute | Medium | One at a time, in a quiet window, checking peaks and not just averages. |
| Shut down an idle environment | Medium | Find the owner first. Idle is not the same as unused; some things wake weekly. |
| Change automatic scaling limits | Medium to high | Only with someone who knows the traffic pattern. This is how you cause an outage while saving money. |
| Delete anything you cannot identify | High | Do not. Find the owner. An unexplained resource is a question, not waste. |
The last row is the one that matters. Every serious incident we have been called into after a cost exercise started with something deleted because nobody could say what it was for.
Making it stay down
A one-off cleanup buys you a few good months and then it climbs back, because nothing changed about how the bill grows. The guardrails are more valuable than the cleanup.
- Budget alerts that reach a human, at a percentage of expected spend rather than after the invoice. Send them somewhere people read.
- Tag everything with an owner, and treat an untagged resource as a fault to be fixed rather than a mystery to be tolerated.
- A monthly look at the bill by someone who understands the systems. Twenty minutes. This alone catches most of it.
- Retention and lifecycle rules by default, so new storage inherits a limit rather than needing a decision.
- Non-production environments that switch themselves off in the evening and at weekends, which is a large saving for almost no risk.
- A named budget owner who can actually stop spend. The gap between who notices and who can act is where months of waste live.
If the underlying problem is that nobody would know until the invoice arrived, that is a monitoring gap rather than a cost one, and our monitoring and reliability work is aimed at exactly that. The cleanup itself is cloud cost optimisation.
Not for you if
Worth saying plainly at the end: nobody reaches this article because their team is careless. Cloud costs are designed to be easy to start and hard to read, resources accumulate faster than anyone can track by memory, and the invoice arrives a month after the decision that caused it. That is a systems problem, and the guardrails above are the fix.
