Skip to main content
How long a virtual tag takes to process is a direct function of how much data it covers and how complex it is. A few configuration choices—backfill window, tag breadth, nesting depth, and virtual tag type—drive that cost, and choosing them well keeps tag changes fast as your account grows.
This guide assumes you are familiar with the Virtual Tags feature reference and the tagging examples.

How Vantage Processes Virtual Tags

When you save a virtual tag, Vantage reapplies it across the cost data in its scope, reprocessing each affected billing data import. A few factors determine how much work each save creates:
  • Backfill window: Billing Period Backfill controls how far back the tag is reapplied. A multi-year backfill covers significantly more data than a few months.
  • Tag breadth: Each value, each collapsed key, and each filter inside a tag adds to the work required to apply it. More values usually mean more work, but what matters most is how many cost rows (the individual line items in your cost data) fall in scope and, for allocations, how many targets each row splits into. As a result, a small tag that matches a huge number of rows or fans out into many allocation targets can cost more than a larger one. Complex filter operators (flexible match, contains) also take longer to evaluate than equality.
  • Nesting depth: When one virtual tag references another, the referenced tag has to be processed first. Every additional level of nesting adds another full run over the data in scope (a “pass”).
  • Virtual tag type: Custom Value and Tag Key Collapsing tags are lightweight: they map or copy values without changing how many cost rows exist. Allocations do more work because they split each matched cost row into multiple rows, one per team, project, or other target the cost is spread across. That added row volume is the real driver. Percent-Based allocations are usually cheap because they split across only a handful of fixed percentages. Cost-Based and Business Metrics-Based allocations also aggregate a driver (spend or a business metric) and can fan each row out across many targets, so they take longest.
Reporting is mostly separate from processing: once a tag is applied, Cost Reports, segments, and saved filters read the result directly, so report performance depends largely on filter operators and provider scope. The main exception is allocations: because they split costs into many more rows, a report that groups or filters by an allocated dimension reads more data and can run slower than the same report over the same costs without that grouping. In addition, the more targets the allocation spreads across, the bigger the effect.

Selecting the Right Virtual Tag Type

Picking the right type for each use case is the choice that has the biggest effect on processing time. The following table lists each type from fastest to slowest to process.
When the split between teams is fixed (a negotiated chargeback ratio, a contractual percentage), use Percent-Based rather than Cost-Based. Same result, much less processing.
The hierarchies that scale best are flat and intentional. Add nesting only when the relationship is dynamic, that is, when an underlying mapping changes often enough that maintaining it in one place is worth a serial processing pass.

Start with a Flat Core Set of Tags

For most organizations, a small core set of five flat virtual tag keys covers most reporting needs. Keep each one independent, with no nesting between them, so they don’t depend on each other and edits don’t cascade across tags. Each of the above tags is a Custom Value tag (or a Tag Key Collapsing tag if your underlying provider tags have casing variations). Build the core set first and resist adding more until you have evidence that a sixth key is needed.

Nest Only When the Mapping Is Dynamic

The classic case for nesting is applicationbusiness-unit. Applications change ownership across business units more often than business units appear or disappear, and you want one place to update that mapping. This is a two-level hierarchy. Every time a relevant import is processed, Vantage runs an application pass first, then a business-unit pass. That is acceptable. A four-level hierarchy—resourceapplicationteambusiness-unit—usually is not, because each level adds another processing pass. This nesting limit is a performance guideline, not a hard rule. When a chain starts to feel that deep, look for a layer whose mapping is stable enough to inline into its parent. See the Nested Virtual Tags Example for the full walkthrough.

Use Allocation Chains Sparingly for Chargeback

Allocated tags can reference each other in a chain (for example, TeamSub-Team), which is useful for layered chargeback. Unlike nesting depth, this is a hard limit: a hierarchy can be up to three allocated tags deep. Only allocated tags count toward it, and non-allocated tags (Custom Value, Tag Key Collapsing) don’t, so a chain can be more than three levels deep overall as long as no more than three of those levels are allocations. Chaining allocations is also one of the most expensive things you can do to processing time. Each allocation in a chain expands rows on top of the one before it, and matching against an already-allocated tag costs more than matching a regular tag, so every added link multiplies the work. Avoid mixing many independent allocated tags on the same provider since each one redistributes costs into a separate dataset.
  • Allocation chains are per provider: An AWS allocation chain is independent of a GCP one. You can have a percent-based Team allocation on AWS and a separate cost-based allocation on GCP with no conflict. Non-allocated virtual tags (Custom Value, Tag Key Collapsing) can also span providers freely.
  • Within a single provider, allocated tags can reference each other only when they sit in the same chain: If you already have a Team percent-based allocation on AWS and want to add an Environment allocation that builds on it (for example, to split costs further within a team), structure Environment to chain off Team, referencing Team = Engineering (or similar) in its Output Costs Filter. If a new allocated tag tries to reference allocated tags from two unrelated AWS chains in one configuration, Vantage rejects the save with the error “cannot reference tags from different allocation groups within the same provider (aws).” Two independent allocated chains can still coexist on the same provider (for example, a TeamSub-Team chain and an unrelated Region allocation, as in the Allocation-on-Allocation Example). They just can’t be combined on the same Cost Report. If you try, Vantage returns “Cannot filter or aggregate costs for allocated virtual tags that belong to separate hierarchies.” Analyze each chain in its own report.
    A new allocated tag chains off an existing allocated tag in the same chain.
See the Allocation-on-Allocation Example for the constraints on combining allocated tags on the same report.

Best Practices to Keep Processing Time Predictable

The following recommendations are listed roughly in order of impact. The first three have the biggest effect.
Selecting All Providers on a filter set is convenient, but it tells Vantage to evaluate that filter against every connected provider’s data and makes every provider’s processing depend on the tag keys it references. If a tag’s logic is only meaningful for AWS, scope its filters to AWS.Use All Providers when the underlying logic really does apply uniformly across every provider you have or will ever connect, for example, a team rule that depends only on a team tag every provider already emits.
Billing Period Backfill is the top-level multiplier on every tag processing run. Pick the earliest month you actually report on, not the earliest month Vantage has data for. Extending the backfill later is straightforward, but it reprocesses every import in the resulting window, not just the months you added, so it’s worth setting deliberately up front.For a forward-looking tag (a new team, a new chargeback model that starts next quarter), set the backfill to the current month.
Every nested level adds a serial processing pass on every relevant import. Two levels is fine; three is sometimes justified; four or more rarely pays for itself. If you find yourself building a deep chain, ask whether the deepest layer would be more accurate as a flat tag with its own filter set.
Every save reprocesses the imports in scope, and each round reapplies every tag that applies to those imports, not just the tag you changed. To avoid repeating that work, make all intended changes to a tag before saving instead of saving after each tweak. Changes to separate tags still require separate saves.
Filter operators are not equally fast:
  • is is an exact match Vantage can look up directly (supplying multiple values checks them as a set). Fastest.
  • contains, starts with, and ends with scan the text of every value in scope, so they inspect far more data.
  • flexible match normalizes and pattern-matches every value before comparing, which makes it the slowest.
Use partial matches only when you need to handle inconsistent values you cannot fix upstream. If the variation is in the tag key (env vs Environment), use Tag Key Collapsing instead. It is fast and gives you a single canonical key.
The wrong way to standardize an environment tag with three key variations is to create one virtual tag value per environment with three filters each. The right way is to create one virtual tag with three collapsed keys. Collapsing copies values through automatically and stays correct as new values appear at the provider.Reserve per-value Custom Value filters for when the source-to-target mapping is genuinely many-to-one and would not survive a value being copied through verbatim.
Within a virtual tag, when two rules match the same row, the rule higher in the list takes precedence. Order doesn’t change how much work matching takes, but it does decide which value is applied when rules overlap. Put more specific rules above broader ones so the value you actually want is the one that lands on the row.
Cost-Based and Business Metrics-Based allocations aggregate a driver and split each matched row across every target it touches. If the split between teams is a fixed percentage, a Percent-Based allocation is still an allocation but fans out across only those few percentages, so it produces the same result with much less work.
Using 11 narrow virtual tags that each cover a single team takes longer to process and is harder to reason about than one team virtual tag with 11 values. Consolidate where possible and keep headroom under the default limits of 50 virtual tags per account and 100 values per tag.

Anti-Patterns to Avoid

Convenient by default, slow at scale. Scope each tag to the providers whose data its filters actually match.
A forward-looking tag with a longer backfill reprocesses three years of data on every save for no reporting benefit. Set the backfill to the earliest month you actually report on for that tag.
Each level is sequential. Flatten where possible. If a deep chain feels necessary, look for a level whose mapping is stable enough to inline into its parent.
Every save kicks off reprocessing on every relevant import. Stage all your changes (values, filters, ordering, backfill) before saving, especially for tags with wide backfill windows.
flexible match is the slowest operator. If the variation is in the key rather than the value, use Tag Key Collapsing.
Each allocated tag chain redistributes costs into a separate dataset, and unrelated allocated tags cannot be combined on the same Cost Report. Keep allocated tags inside the same chain when you need them to compose, or use separate reports.

Frequently Asked Questions

Processing time is roughly proportional to billing periods in backfill × integrations whose data the tag could match × values + collapsed keys × nested levels, and for allocated tags it scales further with the number of targets each cost row splits into. A team tag with 30 values, a 12-month backfill, and All Providers across 8 integrations does an order of magnitude more work than the same tag scoped to AWS only with a 6-month backfill. Most multi-hour cases are explained by a combination of wide backfill and All Providers scoping—or, for allocations, a split across many targets that expands costs into far more line items.
No. Backfill is per virtual tag. If business-unit references application and you extend business-unit’s backfill to an earlier period, application keeps its existing backfill. To align history across a nested chain, extend the backfill on each referenced tag first, wait for processing to complete, then extend the parent.
Yes. When you save a tag that other tags reference, Vantage reprocesses the dependent tags as well, in dependency order. This is why nested chains add latency, as edits to a foundational tag ripple through every level above it. More broadly, reprocessing happens per import: when an import is reprocessed, every virtual tag that applies to it reruns, not just the tag you edited. That’s another reason to make all your intended edits to a tag before saving, rather than saving after each tweak.
Yes for processing, and yes at read time when more than one provider is in scope. For tags whose logic genuinely applies to every provider (and every provider you might add), All Providers is the right choice. For tags whose rules will only ever match one or two providers, scoping per provider is faster and stays accurate as you add new providers that should not be in scope.
Order does not change the total amount of matching work, but it does control which rule wins on overlap. Put more specific or higher-priority rules above broader ones so overlapping rules apply the intended value. This is consistent with Virtual Tag Order.
Yes, modestly. Each removed value is one fewer value Vantage has to match each time the tag runs. The bigger wins come from reducing backfill width, tightening provider scope, and flattening hierarchy. Delete-and-consolidate is worth doing alongside those, not instead of them.
Mostly indirectly. By the time a Cost Report runs, virtual tag values are already written into your cost data, so report runtime depends largely on the report’s filter operators and provider scope. Equality filters on a single provider read faster than flexible match filters across All Providers. The exception is allocations: because they split costs into many more rows, a report that groups or filters by an allocated dimension reads more data and can run slower than the same report without that grouping.