Skip to content

Virtual tagging & cost allocation

Virtual tagging attributes cost to a team or category without requiring any tag on the underlying cloud resource. A tag rule matches spend by the dimension your cost data already breaks down by — service, account, usage type, or region — and assigns it a tag_key/tag_value label, such as team → platform. Nothing has to be tagged in AWS, GCP, or any other source for this to work.

Every tag_key works at one grain, the level of detail in the underlying cost data. The grains are service, service and region, service and linked account, usage type, service and usage type, and resource. A rule matches on the dimensions its grain carries, so one rule can match on more than one dimension (for example service and region together). A team tag_key’s rules might each match on service — “anything in Amazon EC2 and Amazon RDS belongs to Platform,” “anything in Amazon SageMaker belongs to ML.” A rule can also match on linked account instead — “account 445566 belongs to Growth” — if that’s how the spend is actually organized.

Two match keys work at any grain: a provider-native tag on the row (tags.<key>, such as an AWS cost-allocation tag) and the cost source itself (cost_source_id, for “all spend from this source”).

If several rules on a tag_key match the same row, the first one wins. Rules are checked in ascending priority order, and ties go to the rule created first.

All the rules for one tag_key have to use the same grain, and the first rule you create sets it. A team tag_key whose first rule matches by service can’t also have a rule at the account grain — mixing grains within one tag_key would double-count spend, since the same dollar can appear in more than one grain’s breakdown.

Once rules exist for a tag_key, every chart and budget that breaks down by that tag_key shows real spend per tag_value — no separate tagging step in the cloud console, no waiting for tags to propagate to the billing export.

Creating, editing, or deleting a tag rule re-attributes your account’s entire cost history the moment you save it. There’s no backfill job to run, no snapshot to rebuild, and no waiting period.

This works because attribution isn’t stored anywhere. Charts, tag breakdowns, unit-economics metrics, the MCP tools, and tag recommendations all apply the current rules to the raw cost data at the moment you ask for a number. Add a rule today, chart January of two years ago, and the new rule applies to every matching row in that range immediately.

Example: you notice a service that’s been running for 18 months was never mapped to a team. You add one rule for it. The team breakdown for all 18 months redraws with that spend attributed — including periods you’d already exported, screenshotted, or reported on.

A budget’s spend figure is a stored rollup, not a live query, so it doesn’t move the instant you save a rule. Two halves, and they behave differently:

  • The current period catches up on its own. Saving a rule triggers a rollup for exactly the budgets that tag key can affect, so in practice the budget card updates right away. If that rollup doesn’t run — a transient failure — the nightly sweep picks it up, making ~24 hours the worst case. Either way the whole period is re-summed from its start, not just the spend since your edit.
  • Closed periods never move. A budget period that has already ended keeps the verdict it had. If June’s budget was exceeded under the old rules, it stays exceeded even though a rule you change in August would have put June under the line.

The frozen closed period is deliberate. An alert that already fired, and that someone already acted on, must not silently flip months later because a tagging rule changed. There’s no “recompute a closed period” action, and a rule edit will never do it as a side effect.

This is the most likely reason a chart and a budget disagree. If a tag breakdown shows a team’s history redrawn but the budget beside it still reads the old figure, check which period you’re looking at: a closed one is frozen by design, the current one is a rollup away. Saving a rule shows a message stating this same distinction — charts now, current-period budget alerts within ~24 hours, closed periods keep their original verdict.

Split rules: dividing shared spend by weight

Section titled “Split rules: dividing shared spend by weight”

Some spend can’t be attributed to one team by matching a dimension at all — a shared Kubernetes cluster, a shared observability platform, shared egress. A split rule divides that spend across multiple tag values by weight instead of assigning it to just one.

Example: a $10,000/month observability bill is split 60% Platform / 40% Growth, because that’s roughly how the two teams’ dashboards and alert volume break down. The rule matches the observability service and carries two destinations instead of one:

tag_value weight share of $10,000
Platform 0.6 $6,000
Growth 0.4 $4,000

Platform’s tag-scoped total for the month includes its other, directly-matched spend plus this $6,000. Growth’s includes its own directly-matched spend plus $4,000. Neither team sees the full $10,000, and the $10,000 doesn’t disappear — it’s fully accounted for between the two.

A split rule’s own name (e.g. “Shared observability bill”) is a display label only. It never receives spend itself. A budget scoped directly to that name reads $0 forever — scope the budget to Platform or Growth instead, since that’s where the money actually lands.

Proportional redistribution: dissolving an Untagged bucket

Section titled “Proportional redistribution: dissolving an Untagged bucket”

Not every dollar matches a tag rule. Spend that matches nothing lands in an Untagged bucket by default. Proportional redistribution is a separate, opt-in setting per tag_key that dissolves a chosen bucket — typically Untagged — into all the other tag values, in proportion to how much each of them has already been attributed.

Example: on a day where Platform has $700 attributed, Growth has $300, and Untagged has $100, turning on redistribution for Untagged splits that $100 70/30 (Platform’s and Growth’s existing shares of $1,000) — Platform’s total becomes $770, Growth’s becomes $330, and Untagged drops to $0 for that day.

Two situations leave the bucket alone rather than forcing an answer:

  • The bucket has no spend for the period — there’s nothing to redistribute.
  • Every dollar for the period is in the bucket — there’s no attributed spend to use as a ratio, so Untagged stays visible on the chart. That’s the accurate answer: there’s nothing to divide it against yet.

Turning redistribution on or off changes charts immediately, since it changes what counts as each team’s spend. Tag-scoped budget cards on that tag_key catch up at the next nightly rollup, about 24 hours later. Unlike saving a rule, changing this setting doesn’t trigger a budget rollup. The change shows up in the account’s activity log.

Redistribution runs per day, not per chart bucket

Section titled “Redistribution runs per day, not per chart bucket”

This is the part that’s easy to get wrong intuitively, so it’s worth stating plainly: splits and redistribution are computed once per UTC day, then that day’s result is what gets summed, grouped, or charted at whatever granularity you’re viewing.

The reason is that proportions taken per day and then summed are not the same as the proportions of the summed period. Take a tag_key with two days of data:

Day Platform Checkout Untagged
Monday $100 $0 $10
Tuesday $100 $100 $0

Redistributed per day, Monday’s $10 goes entirely to Platform (Checkout had $0 that day, so 100% of the ratio is Platform’s). Tuesday has nothing to redistribute. Platform’s two-day total is $100 + $10 + $100 = $210.

Redistributed across the summed two-day period instead, Platform would have $200 already-attributed and Checkout $100, so the $10 would split 2:1 — Platform would get $6.67 of it, for $206.67, not $210.

Plutus always uses the first calculation. Fixing the unit at one day is what makes a daily chart, a monthly chart, and a tag-scoped budget agree on the same number for the same spend.

One consequence of this: an hourly view is finer than the unit redistribution operates at, so a day’s redistributed share is spread back across that day’s hours following each tag value’s own hourly usage profile for that day — not evenly. If Platform’s usage on Monday was concentrated in the evening, its share of Monday’s redistributed Untagged spend lands mostly in evening hours too, not spread flat across all 24. This is intentional: the shared cost is meant to land where a team was actually active, not smeared evenly across a day it may not have been running anything. An hourly chart under redistribution won’t match the raw per-hour spend for that reason — that’s expected, not a bug. Totals still reconcile at the day level; individual hours are not independently guaranteed to.

For any given scope and period, the sum of spend across all tag values equals the total spend for that scope. This holds whether or not splits or redistribution are involved — splits preserve it because a rule’s weights always sum to 1, and redistribution preserves it because it only moves dollars between existing buckets, it never creates or removes any. A chart broken down by tag and the plain cost total above it will never disagree about how much was spent in total, only about how it’s divided up.

A target is a percentage a tag value’s share of spend is meant to stay under — “infrastructure should be under 20% of what the team tag key attributes.” Set one on the Cost Tags page: open a tag key’s settings panel, and each of its tag values gets a target field and a meter showing actual against target, with actual reading as over once it passes the target line.

Two things define what the number means:

  • The denominator is the total spend across every tag value the page shows for that key, not the whole account. A 20% target on team → infra means 20% of that total. Untagged is in the denominator unless redistribution dissolves it into the other values. Spend from sources or dimensions that key doesn’t cover isn’t included.
  • The window is the trailing 90 days, the same window the Cost Tags page itself charts. The actual percentage is computed from the numbers already on the page rather than recalculated separately, so the meter and the breakdown beside it can’t disagree.

Targets are presentation only. Nothing fires when a value goes past its target — no alert, no notification, no state change. If you want to be told, create a budget: a budget compares spend against a fixed dollar cap and notifies a channel, which is a different question from a share-of-total ratio. The two are complementary and completely independent.

Two shapes to expect:

  • A split rule’s values are listed individually, because that’s where the money lands. The split rule’s own display label doesn’t appear as a target row — it never receives spend.
  • A tag key’s redistribution bucket can’t have a target. Its spend is dissolved into the other values, so a target on it would read as roughly 0% no matter what. The control is disabled with that reason shown, rather than accepting a target that could never be met.

Setting or clearing a target needs the member role, and the change is recorded in the account’s activity log.

A budget scoped to a tag value (including a team-scoped budget, which is a tag-scoped budget under the team tag_key) is computed with the same rules described above — the same weighted split shares, the same per-day redistribution. A budget and the chart shown next to it are computed the same way and won’t disagree about the same spend.

Two things to know when working with tag-scoped budgets specifically:

  • A budget scoped to a split rule’s own display name (not one of its weighted destinations) reads $0, for the reason described under Split rules above.
  • Splitting and redistribution both work in fractional dollars, and each tag-scoped budget rounds once at the end. That means the sum of several tag-scoped budgets can be a cent or two off from the equivalent account-scoped total. That’s expected rounding, not a reconciliation error.

See Budgets & alerts for how a tag-scoped budget’s spend-so-far figure is computed and rolled up.