Skip to main content

Resource

Best Practices

Naming conventions, depth guidelines, and common mistakes to avoid when working with gameplay tags.

Naming conventions

Format

Gameplay tags use PascalCase with dots as separators. No spaces, no hyphens, no underscores in the tag string itself.

Example
Verdict
Why
Ability.Melee.LightAttackGoodPascalCase, dot-separated, descriptive
ability.melee.light_attackBadLowercase, underscores
Ability-Melee-LightAttackBadHyphens instead of dots
LightAttackBadNo hierarchy, can't use parent matching

Root categories

The first segment of a tag is the category. It's ideal to declare root categories as native tags in C++ so they exist before any config file loads. Categories are nouns. Leaves can be nouns, adjectives, or past participles.

Category
Purpose
AbilityAbility identification, activation states, failure reasons
CooldownCooldown identifiers per ability or slot
DamageDamage type classification
EventGameplay events sent between systems
GameplayCueVFX/SFX feedback (engine-required prefix)
InputTagMapping Enhanced Input actions to gameplay
MovementMovement mode tags
SetByCallerData-passing tags for GE modifiers
StateActor state flags (dead, stunned, aiming)
StatusStatus effects (burn, poison, bleed)
UICommonUI layer and action routing
WeaponWeapon identification and attributes

Tag depth

Most tags land at 3 levels deep. Going deeper than 4 usually means the hierarchy is doing too much work and should be split into separate categories.

Depth
Verdict
Example
1Too flatDamage
2GoodDamage.Fire
3IdealAbility.ActivateFail.Cooldown
4AcceptableGameplayCue.Weapon.Impact.Metal
5+Too deepSplit into separate categories

Tags vs enums

Use gameplay tags when

  • +The set of values will grow over time
  • +You need hierarchical matching (Damage catches Damage.Fire)
  • +Designers need to add new values without code changes
  • +Multiple systems need to query the same state
  • +You want data-driven configuration via .ini or data tables

Use enums when

  • −The set is fixed and small (for example, North/South/East/West)
  • −You need switch statement exhaustiveness at compile time
  • −Performance matters in a tight inner loop
  • −Values map 1:1 to associated data (enum-indexed arrays)

Tag governance

Treat the tag dictionary the same way you treat a database schema. Changes ripple across every system that references a tag.

  • 01Keep a single source of truth: either DefaultGameplayTags.ini or a native tag module in C++.
  • 02Use separate .ini files per domain or team: Config/Tags/AbilityTags.ini, Config/Tags/AITags.ini.
  • 03Use restricted tags for root categories that only specific modules can extend.
  • 04Review tag additions in code review. A new tag affects every system that queries its parent.
  • 05Every tag deserves a DevComment. This helps other developers, and future you.

Anti-patterns

Encoding data in tag namesDamage.50
Tags identify categories, not values. Use SetByCaller for numbers.
Flat tags with no hierarchyFireDamage
You lose parent matching. Damage.Fire is queryable by Damage.
Duplicating meaningState.Dead and Status.Death
Systems check different tags for the same state, leading to desync.
Hardcoding tag strings in Blueprint
Use tag variables or native tag references. Raw strings break silently on rename.
Tags without descriptionsState.X3
Six months from now nobody will remember what this means.
Using TArray<FGameplayTag>
Use FGameplayTagContainer instead. It has optimized HasTag, HasAny, and HasAll.

Unreal Directive is free and ad-free.

If it saved you time, you can help keep it that way.

Donate