Unreal Engine's Mass: Fragments & Tags (Components)
July 02, 2026 · 9 min read
A description of Fragments within Unreal Engine's Mass.
This blog post was written in reference to Unreal Engine 5.8
Overview
Fragments are intended to be just plain ol data with no functionality, it only should hold properties that will be modified by external system’s and Processors. Fragments are allowed to have functions but that contradicts the point of an ECS design so my recommendation is to keep this light.
When an entity is migrated between chunks they are memcpy’d, so keeping a Fragment trivially copyable is important!
You can have non-trivially copyable variables within Fragments but be prepared for handling your use cases appropriately(IE: There will be dragons).
Array containers automatically fall into this camp of non-trivially copyable due to their dynamic sizing, if it’s a static array(the size doesn’t change), then it’s trivially copyable.
Fragment Type | Typename | Where is it stored? | Modifiable at Runtime? | Designer editable? | Description/Notes |
|---|---|---|---|---|---|
Default / Regular Fragment |
| One per entity. | Yes | Yes but only via Trait’s or external systems that expose it directly. | It’s a per-Entity element of state. |
Constant Shared Fragment |
| One copy, deduplicated by value. | No, Read Only. | Yes, same rules as FMassFragment. | Intended as a read only configuration for a Fragment that is shared by multiple Entities. Essentially the “Read only DataAsset” Fragment’s of Mass. |
Shared Fragment |
| One copy per Shared Instance. | Yes | Yes, same rules as | Like the constant shared Fragment, but not constant. Useful for things like team score, team ID’s, a global mesh, really any shared data that a group needs quickly and we only need to set it in one place. |
Chunk Fragment |
| One per memory chunk. | Yes | No | Intended as an aggregate of what a Processor computes for a single chunk of Entities. Useful for LOD’s, tick bookkeeping, etc. |
Read/Write Access
You can also specify thread access rules using C++ traits
(you can see an example of this in MassRepresentationFragments.h). These traits live on Shared fragments
(TMassSharedFragmentTraits) and external Subsystems (TMassExternalSubsystemTraits), not on a plain FMassFragment.
For a Shared Fragment, the engine only honors GameThreadOnly; ThreadSafeWrite takes effect on external Subsystems.
USTRUCT()
struct FMySharedFragment : public FMassSharedFragment
{
GENERATED_BODY()
// ...
};
// For shared fragments the engine only reads GameThreadOnly.
// (ThreadSafeWrite is honored on TMassExternalSubsystemTraits, for subsystems.)
template<>
struct TMassSharedFragmentTraits<FMySharedFragment> final
{
enum
{
GameThreadOnly = true
};
};Tags
There are also Fragments called Tags(FMassTag) which operate in a different space:
- They are not stored per entity but instead per Archetype for filtering.
- They do not hold any data, its essentially a filtering tag applied to a set of entities for quick and easy queries that require little to no data evaluation.
- They are not modifiable or usable in the editor since they don’t have a concept of state other than basic
USTRUCTtype filtering checking.
Since they are used per Archetype, adding/removing a Tag from an entity will cause the entity to be moved into a new or already existing chunk of allocated memory.
Type | Memory Usage per Entity | What Changes? | Cost |
|---|---|---|---|
Tag | 0 Bytes | Change the Archetype, causing an entity migration. | Can be expensive operation due to the move to a newly allocated chunk. |
Fragment(with a boolean) | +1 Bytes | No Archetype Change, all in the same chunk. | Cheap operation, just writing to a value. No new memory allocations. Uses more memory overall. |
Sparse Fragments
There are two provided Sparse Fragments:
FMassSparseFragment: Per-Entity Fragment data, but held in separate side storage (FSparseElementsStorage) rather than in the Archetype chunk like a regular Fragment.FMassSparseTag: Presence is tracked per Archetype chunk in a per-Entity bitmask.
The defining trait of both is that they are not part of the Archetype’s composition, so adding or removing one never causes an Archetype change (no chunk migration).
To make your own type sparse, derive it from FMassSparseFragment (Fragments) or FMassSparseTag (Tags).
The runtime check for whether a type is already sparse is ::IsSparse() in Mass/EntityElementTypes.h.
Adding/Removing Tags/Fragments at Runtime
It is very often necessary to add/remove a Tag and/or Fragment(or multiple in a batch) at runtime. Currently, there are three common ways to achieve this with additional sub-pathways and approaches not mentioned (this is a “many ways to achieve this goal” situation):
Scope | Outside a Processor (external / game thread) | Inside a Processor’s |
|---|---|---|
Single Entity |
|
|
Multiple Entities |
|
|
Behavior | Mutates the Archetype immediately. Asserts ( | Queued on the Command Buffer and flushed after the phase, so it is safe mid-iteration. |