Someone in every company eventually says this out loud. Usually it's the CFO. Sometimes it's a VP of engineering, or the unlucky engineer who got handed "own our cloud costs" on top of their actual job. The bill comes in, it's up again, the spreadsheet has eleven tabs, and someone finally says:
"Stop. I don't want another spreadsheet. I need one picture that shows where the money goes."
It's a completely reasonable request. It's also strangely hard to satisfy with the tools most teams already have. This post is about why, where the money usually turns out to be going, and what that one picture actually looks like.
The bill answers "how much". The question is "where"
A cloud bill is a flat table — a very big one. An AWS Cost and Usage Report can run to millions of rows, and every row is precise: this resource, this hour, this rate. If your question is "how much did we spend on EC2 in July", the tools answer instantly.
But "where does the money go" is a different kind of question. A dollar enters the company as one line on an invoice and then travels: through a provider, into an account, into some kind of resource, and finally — ideally — onto somebody's team. It's a path, not a number. Flat tables don't show paths.
Native tools slice one dimension at a time. Cost Explorer will show you spend by service. Or by linked account. Or by one tag. Each view is true, and each view is a dead end, because the question in the meeting is always a path through several dimensions at once: which team's non-prod environments, in which account, are driving the compute growth? Answering that with one-dimensional views means six tabs and a join you perform in your head. The join in your head is where the meeting dies.
So people fall back to the spreadsheet. Someone brave builds a pivot table; it's accurate for a week, then a re-org or a new account lands and it quietly becomes fiction that everyone still forwards.
Where the money usually goes
We look at a lot of cloud bills. The leaks are boringly consistent:
Non-prod that never sleeps. A week has 168 hours; a working week has maybe 50. Dev, staging, QA, and demo environments left running 24/7 are paying for roughly 120 hours a week that nobody uses. Across the bills we see, this is routinely the single largest controllable chunk of spend.
Unattributed spend. Resources with no owner tag, no team, no cost center. Nobody owns it, so nobody questions it, so it grows. It's common for 10–30% of a bill to be attributed to nobody at all.
Zombies. Unattached volumes, idle load balancers, snapshots from three years ago, NAT gateways still charging for data processing on traffic that stopped mattering.
"Just in case" sizing. Instances sitting at 6% CPU because someone doubled them during an incident in 2024 and nobody ever walked it back.
On-demand pricing for permanent workloads. A baseline that has run every hour for two years, still billed like it's an experiment.
Industry surveys have put overall cloud waste at around a third of spend for years. The exact percentage matters less than the pattern behind it: waste concentrates wherever attribution is weakest. Money that isn't visibly somebody's money is the money that leaks.
The one picture is a Sankey diagram
You've probably seen national energy-flow charts: all of a country's energy enters on the left and splits into homes, industry, transport — and "losses". That chart type is a Sankey diagram: flows drawn as ribbons whose width is proportional to the amount.
It's the right picture for cloud spend for one reason above all: conservation. Everything entering the left edge has to exit on the right. Nothing gets to hide.
For a cloud bill, the useful version has four columns:
Provider → Account → Resource type → Team
The entire invoice enters as one wide band and fans out until every dollar lands on a team. And when a chunk of it lands on a node called Unattributed, that ribbon is drawn exactly as thick and exactly as visible as everyone else's. That's the point. The most important stream in the picture is the one no dashboard was ever proud of.
Reading it requires no training, which is the real feature. Thick ribbon → go look. Your eye runs the query. A CFO parses it in about ten seconds, without anyone explaining what an availability zone is.
(screenshot placeholder: 4-column cost Sankey — Provider → Account → Type → Team, with a visible Unattributed ribbon)
What a good version needs
Whether you build or buy, the checklist is the same — because a static Sankey answers exactly one question, and then someone in the room asks the next one.
- Reorderable columns. Provider → Account → Type → Team is the default path, but some weeks the question is regional, or about purchase types (is our savings-plan coverage where it should be?), or needs to go all the way down to individual resources.
- Click to drill. The picture should be the filter. Click an account's node and the whole diagram narrows to money flowing through it, with a breadcrumb trail so you can back out one hop at a time. If drilling means a separate wall of dropdown filters, people stop after question one.
- A waste overlay. Show which ribbons contain reclaimable money — idle, oversized, schedulable — and how much. Otherwise the picture says where money goes but not which flows you can do something about this quarter.
- Unattributed as a first-class stream, with a toggle that makes it impossible to ignore. It shrinks when it's embarrassing.
- Live data. A picture "as of Tuesday" gets re-litigated. A live one gets acted on.
- A URL that reproduces the exact view. The picture only works if both sides of the table are looking at the same one, and the cheapest way to guarantee that is a link pasted into Slack an hour before the meeting.
Building it yourself
Genuinely doable, and a fair weekend project for a v1: export billing data (CUR on AWS, billing export on GCP), aggregate it with a GROUP BY over your three or four dimensions, and feed the source–target pairs to d3-sankey, Plotly, or ECharts.
The chart is the easy 20%. Three things make up the other 80%:
- The Type → Team hop is only as good as your tagging. The Sankey will faithfully draw your allocation gaps as one giant Unattributed ribbon. That's a feature, but brace for it.
- Keeping it live. Scheduled exports, an aggregation job, cache freshness. The v1 that's a static HTML file goes stale in a week and dies like every pivot table before it.
- Interactivity. Drill-down, breadcrumbs, view state in the URL. This is where a weekend becomes a quarter.
How we ended up building it into ZopNight
We heard "just show me one picture" often enough that we built it into ZopNight's cost reports. The Cost Breakdown card has a Trend / Flow toggle — Trend is spend over time, Flow is the Sankey.
Against the checklist above:
- A layout picker for the four columns: Provider → Account → Type → Team by default, with variants that swap in Service, Region, or Purchase type, or go down to individual resources.
- The chart is the only filter surface. Click a node or a ribbon and the diagram narrows; breadcrumb chips show the drill path; back out one column at a time or clear all.
- The savings overlay stripes nodes and ribbons in red, proportional to reclaimable spend. The thick red parts are your to-do list, already sorted.
- Hover anything and an inspector shows the dollars and its share of source and target. Where the dimension is one our recommendations engine can actually filter on — a resource type, a cloud account — there's a "$X reclaimable" callout that deep-links to those exact recommendations. Where it can't act (a region, a purchase type), the callout is hidden rather than teasing a number with no button behind it.
- An Unattributed highlight toggle, for that conversation.
- The whole view state lives in the URL — layout, drill path, overlays. Paste it in Slack and finance opens exactly your view.
- It's served live from the raw cost records every time it renders. No "updated yesterday" footnote.
(screenshot placeholder: Flow view with the savings overlay on, hover inspector showing a "$X reclaimable" callout)
If you'd rather build than buy: the checklist in the previous section was our spec. Steal it.
The picture was never the point
The "one picture" request isn't really about a chart. It's finance and engineering asking to argue about the same object for once — one artifact where "how much", "where", and "what can we do about it" are visible at the same time. Once that exists as a link, "where does the money go" stops being a two-week research project. It's just a thing you open.
FAQ
How do I see where my AWS spend is actually going?
Group billing data by several dimensions at once — account, resource type or service, and team (via tags) — instead of one at a time. Single-dimension views like the Cost Explorer defaults answer "how much", not "where". A flow (Sankey) view across 3–4 dimensions is the fastest way to see the full path from invoice to team; build one from a CUR export, or use a cost tool with one built in.
What is a Sankey diagram in cloud cost management?
A flow chart where ribbon width is proportional to dollars, tracing spend across columns such as Provider → Account → Resource type → Team. Its conservation property — everything that enters must exit — is what makes it useful for bills: unallocated and wasted spend can't hide, it shows up as its own visible stream.
Why doesn't AWS Cost Explorer show me this?
Cost Explorer groups by one dimension at a time (two, with effort). It slices; it doesn't draw paths. For multi-hop questions — which team, in which account, spending on what — you either export the CUR and build multi-dimensional views yourself, or use tooling that renders the flow directly.
What is unattributed cloud spend, and how do I fix it?
Spend that no team, tag, or cost center owns. It's the most dangerous part of a bill, because unowned money is unmanaged money — it grows without anyone deciding it should. The fix: a small mandatory tag set enforced at provision time, allocation rules for genuinely shared costs, and above all making the unattributed number visible. It shrinks when it's embarrassing.
How much cloud spend is typically wasted?
Industry surveys have hovered around 30% for years. In our experience the largest controllable chunk is non-production capacity running around the clock: a week has 168 hours and a working week around 50, so an always-on dev environment pays for roughly 120 unused hours every single week.
How do I present cloud costs to finance without a 40-tab spreadsheet?
Agree on the dimensions finance actually thinks in — team, product, environment, not instance families — and bring one live picture of the flow through those dimensions, with a link that reproduces it. Line items are for auditing. Flows are for decisions.
What's the fastest way to cut cloud costs once I can see them?
Usually in this order: park non-production environments on nights and weekends (scheduling is the rare fix with no performance trade-off), delete zombie resources, rightsize the chronically idle, then fix commitment coverage for the steady baseline. But visibility comes first — teams that cut before attributing tend to cut the wrong things.
Top comments (0)