Resource
How to register gameplay tags in your project. Covers .ini files, Data Tables, C++ native declarations, and restricted tags.
This is the most common approach and the one designers can edit without touching code. Tags go in Config/DefaultGameplayTags.ini or in separate files under Config/Tags/.
[/Script/GameplayTags.GameplayTagsList]
GameplayTagList=(Tag="Ability.Melee.LightAttack",DevComment="Basic light melee attack")
GameplayTagList=(Tag="Ability.Melee.HeavyAttack",DevComment="Charged heavy melee attack")
GameplayTagList=(Tag="Ability.Ranged.PrimaryFire",DevComment="Primary weapon fire")
GameplayTagList=(Tag="Damage.Physical",DevComment="Physical damage parent tag")
GameplayTagList=(Tag="Damage.Physical.Melee",DevComment="Melee physical damage")
GameplayTagList=(Tag="State.Dead",DevComment="Character is dead")For larger projects, it's ideal to split tags into domain-specific files. The engine loads all .ini files referenced in your project settings.
[/Script/GameplayTags.GameplayTagsList]
GameplayTagList=(Tag="Ability.ActivateFail.IsDead",DevComment="Owner is dead")
GameplayTagList=(Tag="Ability.ActivateFail.Cooldown",DevComment="On cooldown")
GameplayTagList=(Tag="Ability.ActivateFail.Cost",DevComment="Cannot afford cost")Data Tables use the GameplayTagTableRow row structure. Add the Data Table to Project Settings > Gameplay Tags > Gameplay Tag Table List.
TagThe full tag string (for example, Ability.Skill.Fireball)DevCommentDescription shown in the tag pickerUse Data Tables when designers need to add tags from the editor without editing config files. Use .ini files when you want version-control-friendly diffs.
Native tags are resolved at initialization, so there is no runtime dictionary lookup. It's ideal to use this for root categories and tags that must exist before any config loads.
#pragma once
#include "NativeGameplayTags.h"
UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_Ability_ActivateFail_IsDead);
UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_Ability_ActivateFail_Cooldown);
UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_State_Dead);
UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_Damage_Physical);#include "MyProjectTags.h"
UE_DEFINE_GAMEPLAY_TAG_COMMENT(TAG_Ability_ActivateFail_IsDead,
"Ability.ActivateFail.IsDead",
"Ability failed because the owner is dead.");
UE_DEFINE_GAMEPLAY_TAG_COMMENT(TAG_Ability_ActivateFail_Cooldown,
"Ability.ActivateFail.Cooldown",
"Ability is still on cooldown.");
UE_DEFINE_GAMEPLAY_TAG_COMMENT(TAG_State_Dead,
"State.Dead",
"Character is dead.");
UE_DEFINE_GAMEPLAY_TAG_COMMENT(TAG_Damage_Physical,
"Damage.Physical",
"Physical damage parent tag.");For tags that only one .cpp file needs, use the static variant. No header declaration required.
UE_DEFINE_GAMEPLAY_TAG_STATIC(TAG_Event_Explode, "Event.Explode");FGameplayTag::RequestGameplayTag does a dictionary lookup every call. Cache the result if you must use it. Native tags are the preferred alternative.
// Avoid calling this repeatedly in a loop
FGameplayTag DamageTag = FGameplayTag::RequestGameplayTag(FName("Damage.Physical"));
// Better: cache it
static const FGameplayTag DamageTag = FGameplayTag::RequestGameplayTag(FName("Damage.Physical"));Restricted tags prevent other modules or team members from adding children to a root tag without permission. This is useful for large teams where tag sprawl is a risk.
[/Script/GameplayTags.RestrictedGameplayTagsList]
RestrictedGameplayTagList=(bAllowNonRestrictedChildren=false,Tag="Ability",DevComment="Root ability category - restricted to gameplay module")
RestrictedGameplayTagList=(bAllowNonRestrictedChildren=false,Tag="GameplayCue",DevComment="Root cue category - restricted to VFX module")When bAllowNonRestrictedChildren is false, only other restricted tag entries can add children under that root. The editor shows a lock icon next to restricted tags.