Course outline · 0% complete

0/27 lessons0%

Course overview →

Watching the bill: tags, budgets, and Cost Explorer

lesson 8-3 · ~8 min · 24/27

The bill is one number until you make it talk

AWS's invoice arrives as a total. When it jumps from $80 to $310, the number itself tells you nothing: which team, which project, which forgotten experiment? Companies lose real money to exactly this opacity, and "why did the bill go up" lands on an engineer, often a junior one, every single month. This lesson is the toolkit for answering it in minutes instead of an afternoon.

Three tools, all free:

  • Tags are key-value labels you attach to any resource at creation: project=api, team=growth, env=staging. Once a tag key is activated for cost allocation, every line of spending carries the label.
  • Cost Explorer is the console's bill browser: it charts spending over time and, crucially, groups by tag or by service, turning the one number into a breakdown.
  • AWS Budgets sends alerts when actual or forecasted spend crosses a threshold you set. The billing alarm from lesson 8-2 was the minimal version, and budgets are the same idea with per-project scoping.

Grouping costs by tag

This is what Cost Explorer does with cost-allocation tags, in miniature: take every charge with its project tag and print a per-project table.

costs="api:2160 web:87 data:3900 untagged:1450"
for entry in $costs; do
  project=${entry%%:*}
  cents=${entry#*:}
  printf '%-9s $%d.%02d\n' "$project" $((cents / 100)) $((cents % 100))
done

Output

api       $21.60
web       $0.87
data      $39.00
untagged  $14.50

The %-9s format left-aligns each project name in a 9-character field so the dollar amounts line up in a column. Small formatting details like that are why a generated report gets read and a wall of ragged text does not.

The breakdown immediately answers a question the invoice total cannot. data is more than half the bill, so any conversation about reducing spend starts there rather than with a general instruction to be careful.

The untagged problem

That untagged line is the classic failure: resources created in a hurry carry no labels, so their cost belongs to nobody, and unowned spending is exactly the spending nobody turns off. The fixes teams actually use: agree on 2-3 mandatory tag keys, bake them into every deployment template so nothing is created by hand, and review the untagged bucket in Cost Explorer monthly until it shrinks toward zero.

Two more habits close the loop:

  • A budget per project with an alert at, say, 80% of the expected spend. Forecast-based alerts fire before the money is gone: AWS extrapolates the month's spending rate and warns when the projection crosses your line.
  • A weekly two-minute Cost Explorer glance, grouped by service. A NAT gateway (lesson 5-2) quietly processing terabytes, or a forgotten instance (lesson 8-2's trap 1), shows up as a line that grew when nothing shipped.

Totalling the bill and the untagged share

This finishes the audit script: it totals every project's cents and records the untagged amount as the loop passes it.

costs="api:2160 web:87 data:3900 untagged:1450"
total=0
untagged=0
for entry in $costs; do
  cents=${entry#*:}
  total=$((total + cents))
  if [ "${entry%%:*}" = "untagged" ]; then untagged=$cents; fi
done
printf 'total bill: $%d.%02d\n' $((total / 100)) $((total % 100))
echo "untagged share: $((untagged * 100 / total))%"

Output

total bill: $75.97
untagged share: 19%

Reading the loop

  • ${entry#*:} strips everything up to the colon to get the amount, and ${entry%%:*} strips from the colon onward to get the project name. The two expansions cut the same string from opposite ends.
  • The percentage is computed as untagged * 100 / total rather than untagged / total * 100, because integer division would make the second form zero. Multiplying first is the standard fix in integer arithmetic.
  • Nearly a fifth of this bill has no owner. In real accounts that share is often higher, which is why mandatory tags are usually the first cost-control policy a company adopts.

A budget alert that fires before the money is spent

The alert is not broken. It is a forecast alert.

$21 spent by day 10 is about $2.10 a day, which projects to roughly $65 by day 31, past the $50 line. Forecast alerts extrapolate the current spending rate to the end of the month and compare that projection against the threshold.

Warning now is the entire point, because there is still time to turn something off. An alert that waited for the real $50 to arrive would fire around day 24 with the month nearly over and most of the money already spent.

The habit that follows is to set the threshold at what you are willing to spend rather than at what you expect to spend. A forecast alert at your comfort limit gives you three weeks of warning, and one at your expected spend gives you a monthly notification that nothing is wrong.