Unreal coding standards
Match Epic's C++ conventions so code reads like the engine and the rest of the project. The
overriding rule: match the surrounding code first; these are the defaults when nothing
else is established.
Related skills: ue-cpp-fundamentals, ue-core-types-and-containers, ue-module-and-build-system.
When to use this skill
- Writing any new UE C++ header or source file.
- Reviewing or cleaning up code for style consistency.
- Choosing names for types, members, functions, or files.
- Structuring includes and forward declarations in a header.
Type prefixes (mandatory for reflected types)
UHT enforces prefixes for reflected types; mismatches are a compile error.
| Prefix |
Type |
Engine example |
U |
UObject subclass (non-actor) |
UActorComponent (Components/ActorComponent.h:160) |
A |
AActor subclass |
AActor (GameFramework/Actor.h:282) |
F |
Plain struct or non-UObject class |
FAttachmentTransformRules (Engine/EngineTypes.h:75) |
E |
Enum / enum class |
EAttachmentRule (Engine/EngineTypes.h:62) |
I |
Abstract interface class |
IInterface_AssetUserData (Interfaces/Interface_AssetUserData.h:22) |
T |
Class template |
TArray (Containers/Array.h:767) |
S |
Slate widget |
SWidget, SCompoundWidget |
b |
Boolean variable |
bReplicates (GameFramework/Actor.h:593) |
The word after the prefix is PascalCase. The class name without its prefix must match the
filename: AMyPawn → MyPawn.h. Typedefs take the prefix appropriate to their underlying type.
Full prefix rules, interface pairing, enum value style, and template parameter conventions:
references/naming-conventions.md.
Naming
- PascalCase for every identifier — types, functions, member variables, local variables,
and parameters. No
m_ prefix, no camelCase, no snake_case.
- Booleans carry the
b prefix: bIsDead, bHasKey, bReplicates.
- Functions with a bool return ask a question:
IsAlive(), ShouldClearBuffer().
- Output reference parameters carry
Out: void GetItems(TArray<FItem>& OutItems).
- Type and variable names are nouns; function names are verb phrases.
- Be descriptive; avoid abbreviations except established ones (
AI, HUD, LOD, GC).
- Macros are
UE_ALL_CAPS_WITH_UNDERSCORES.
Formatting
Allman braces — opening brace on its own line for every construct. Always brace single-statement
blocks:
void AMyActor::BeginPlay()
{
Super::BeginPlay();
if (bIsReady)
{
DoThing();
}
}
- Tabs (4-character width) for indentation; spaces only for alignment within a line.
- One statement per line.
- Pointer/reference spacing:
FType* Ptr; and const FType& Ref; — */& bind to the type.
- No variable shadowing across scopes.
Switch statements must have an explicit default: branch and document intentional fall-through
with // falls through.
Full formatting rules, switch style, and namespace rules:
references/formatting-and-includes.md.
Language conventions
nullptr — never NULL or 0 for pointers.
override on every overriding virtual. Add final where the class or function should
not be further overridden.
const correctness — const member functions for non-mutating methods; const& for
non-trivial parameters not being copied; never const a by-value return.
TEXT("...") around every string literal that constructs an FString or FName.
enum class over plain enums; back with uint8 if exposed to Blueprints. Values are
PascalCase. Use ENUM_CLASS_FLAGS(EFoo) for bitfield enums with a None = 0 sentinel.
- Engine containers (
TArray, TMap, TSet, FString, FName) over std:: equivalents
in engine-facing code.
auto only where the type is either a lambda, a verbose iterator, or genuinely
indiscernible from context. Always apply const, &, or * explicitly with auto.
- Range-based for is preferred. For
TMap, iterate as for (TPair<K,V>& Kvp : Map).
- Move semantics — use
MoveTemp(X) (UE's std::move) when transferring ownership of
containers or FString into a member or return.
- Lambdas — prefer explicit captures over
[=] or [&]. Captured UObject* pointers
are invisible to the GC. Use CreateWeakLambda / BindWeakLambda for deferred lambdas.
- UObjects via pointer — pass by pointer, not reference. Null is the signal for "absent".
- Portable integer types:
int32, uint32, uint8, float, double, TCHAR; avoid bare
int in serialized or replicated data.
Headers and includes
Header structure (in order)
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h" // 1. CoreMinimal (or fine-grained core headers)
#include "GameFramework/Actor.h" // 2. Engine / module headers this type needs
#include "MyActor.generated.h" // 3. generated.h — ALWAYS LAST
Source file structure
#include "MyActor.h" // matching header first
#include "Components/StaticMeshComponent.h" // then any implementation deps
#pragma once at the top of every header (all target compilers support it).
generated.h must be the last include — UHT requires it. Missing it or putting it in
the middle causes broken generated code.
- IWYU (Include What You Use) — include every header you directly depend on; do not rely
on transitive includes through another header.
- Forward declare in headers where you only need a pointer or reference. In
.cpp, include
the full header. This reduces compile times and dependency coupling.
// Header — forward declare only
class UStaticMeshComponent;
UCLASS()
class MYGAME_API AMyActor : public AActor
{
GENERATED_BODY()
UPROPERTY(VisibleAnywhere) TObjectPtr<UStaticMeshComponent> Mesh;
};
// Source — full include
#include "Components/StaticMeshComponent.h"
Engine evidence: Actor.h lines 5–32 use IWYU-style fine-grained includes ending with
"Actor.generated.h" at line 32; Character.h lines 5–19 show CoreMinimal.h first and
"Character.generated.h" at line 19.
Reflection style
Every reflected class or struct needs GENERATED_BODY() as its first body member. Every
public class in a module needs the module *_API export macro:
UCLASS(Blueprintable, BlueprintType, config=Game)
class MYGAME_API AWeapon : public AActor
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category="Weapon")
void Fire();
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Stats",
meta=(ClampMin="0"))
float Damage = 25.f;
protected:
UPROPERTY(VisibleAnywhere, Category="Components")
TObjectPtr<UStaticMeshComponent> Mesh;
};
Key rules:
- Always set a
Category on any UPROPERTY/UFUNCTION the editor will show. Without it,
properties land in an uncategorized root group.
- Put
meta=(...) last in the specifier list.
- Use
TObjectPtr<T> for UPROPERTY members holding UObject-derived pointers (UE5+ modern
form). Raw T* still works and appears in older code.
- The
*_API macro (e.g. MYGAME_API, ENGINE_API) must appear between class and the
class name for any non-inline public API. UBT expands it to __declspec(dllexport/import).
See references/reflection-and-uht.md for the full specifier
reference, USTRUCT/UENUM/UFUNCTION details, and common UHT errors.
Comments and documentation
// for inline comments; /** ... */ JavaDoc-style comments on public API declarations —
these surface as tooltips for Blueprint-exposed members and in the generated API docs.
- Comment why, not what. Keep comments accurate and current with the code.
- Class comments describe the problem the class solves. Multi-line method comments document
purpose, parameter units/ranges, return value, and any
@warning/@see/@deprecated.
/** Maximum health this actor can have. Modified by difficulty at BeginPlay. */
UPROPERTY(EditDefaultsOnly, Category="Health", meta=(ClampMin="1"))
float MaxHealth = 100.f;
Logging and errors
- Log through a named category with
UE_LOG (ue-logging-and-assertions).
check(Condition) for invariants — aborts in all builds if violated. Never put side effects
inside a check.
ensure(Condition) for recoverable "shouldn't happen" — fires once in non-shipping builds,
returns bool so you can handle the failure.
- Remove debug prints before submitting.
Gotchas
- Wrong or missing type prefix — UHT build error; check U/A/F/E/I/T/S.
generated.h not last — UHT mis-generates or fails outright.
- Missing
GENERATED_BODY() — compile errors from undefined generated symbols.
- Missing
Category on editor-exposed properties — unorganized Details panel.
m_ prefix or snake_case — not Unreal style; use PascalCase.
- Missing
b on booleans — style violation; also breaks naming-based tooling.
std:: containers in engine-facing code — use TArray/TMap/FString instead.
- Omitting
override — silent non-override when a virtual signature drifts.
- Bare
NULL/0 for pointers — use nullptr.
- No
TEXT() around string literals — produces an undesirable narrow-to-wide conversion.
auto overuse — hide types from readers; use only for lambdas, verbose iterators, or
template-context expressions where the type is genuinely unwriteable.
[=]/[&] lambda captures — UObject pointers captured by [=] are invisible to the
GC; deferred [&] lambdas dangle. Use explicit captures and weak wrappers.
References and source material
Engine source (UE 5.8, under Engine/Source/):
Runtime/Engine/Classes/GameFramework/Actor.h:281–282, 288, 306, 593, 891, 1019, 1024
Runtime/Engine/Classes/GameFramework/Character.h:3, 5, 19, 337–338
Runtime/Engine/Classes/Components/ActorComponent.h:3, 23, 27–38, 159–162, 177, 340
Runtime/Engine/Classes/Engine/EngineTypes.h:62, 75
Runtime/Engine/Classes/Interfaces/Interface_AssetUserData.h:3, 16–22
Runtime/CoreUObject/Public/UObject/Object.h:97–100, 106, 129
Runtime/Core/Public/Containers/Array.h:767
Runtime/Core/Public/Windows/WindowsPlatform.h:209–210
Runtime/Core/Public/HAL/Platform.h:1063–1065
Official docs (UE 5.8):
Deep-dive references in this skill:
- references/naming-conventions.md — all prefix rules,
PascalCase details, boolean/enum/function/macro naming, interface pairing.
- references/formatting-and-includes.md — Allman
braces, tabs, switch style, const correctness detail,
#pragma once, include order, IWYU,
forward declarations, API export macros.
- references/reflection-and-uht.md —
UCLASS/USTRUCT/
UENUM/UPROPERTY/UFUNCTION specifier reference, TObjectPtr, GENERATED_BODY(),
and common UHT errors.
1---2name: ue-coding-standards3description: Write Unreal C++ that conforms to Epic's coding standard — type prefixes (U/A/F/E/I/T/S), PascalCase naming, the bBool prefix, enum class style, Allman braces, tab indentation, const correctness, nullptr/override/final usage, TEXT() string literals, include order with generated.h last, IWYU and forward declarations, API export macros (MODULE_API), UPROPERTY/UFUNCTION specifiers with Category, TObjectPtr for UObject members, and engine types over std containers. Use when writing or reviewing any UE C++, naming types or members, structuring headers, or making code consistent with the engine and surrounding project code.4---56# Unreal coding standards78Match Epic's C++ conventions so code reads like the engine and the rest of the project. The9overriding rule: **match the surrounding code first**; these are the defaults when nothing10else is established.1112Related skills: `ue-cpp-fundamentals`, `ue-core-types-and-containers`, `ue-module-and-build-system`.1314## When to use this skill1516- Writing any new UE C++ header or source file.17- Reviewing or cleaning up code for style consistency.18- Choosing names for types, members, functions, or files.19- Structuring includes and forward declarations in a header.2021## Type prefixes (mandatory for reflected types)2223UHT enforces prefixes for reflected types; mismatches are a compile error.2425| Prefix | Type | Engine example |26|---|---|---|27| `U` | UObject subclass (non-actor) | `UActorComponent` (`Components/ActorComponent.h`:160) |28| `A` | AActor subclass | `AActor` (`GameFramework/Actor.h`:282) |29| `F` | Plain struct or non-UObject class | `FAttachmentTransformRules` (`Engine/EngineTypes.h`:75) |30| `E` | Enum / enum class | `EAttachmentRule` (`Engine/EngineTypes.h`:62) |31| `I` | Abstract interface class | `IInterface_AssetUserData` (`Interfaces/Interface_AssetUserData.h`:22) |32| `T` | Class template | `TArray` (`Containers/Array.h`:767) |33| `S` | Slate widget | `SWidget`, `SCompoundWidget` |34| `b` | Boolean variable | `bReplicates` (`GameFramework/Actor.h`:593) |3536The word after the prefix is PascalCase. The class name without its prefix must match the37filename: `AMyPawn` → `MyPawn.h`. Typedefs take the prefix appropriate to their underlying type.3839Full prefix rules, interface pairing, enum value style, and template parameter conventions:40[references/naming-conventions.md](references/naming-conventions.md).4142## Naming4344- **PascalCase** for every identifier — types, functions, member variables, local variables,45 and parameters. No `m_` prefix, no `camelCase`, no `snake_case`.46- **Booleans** carry the `b` prefix: `bIsDead`, `bHasKey`, `bReplicates`.47- **Functions with a bool return** ask a question: `IsAlive()`, `ShouldClearBuffer()`.48- **Output reference parameters** carry `Out`: `void GetItems(TArray<FItem>& OutItems)`.49- **Type and variable names** are nouns; **function names** are verb phrases.50- Be descriptive; avoid abbreviations except established ones (`AI`, `HUD`, `LOD`, `GC`).51- **Macros** are `UE_ALL_CAPS_WITH_UNDERSCORES`.5253## Formatting5455Allman braces — opening brace on its own line for every construct. Always brace single-statement56blocks:5758```cpp59void AMyActor::BeginPlay()60{61 Super::BeginPlay();62 if (bIsReady)63 {64 DoThing();65 }66}67```6869- Tabs (4-character width) for indentation; spaces only for alignment within a line.70- One statement per line.71- Pointer/reference spacing: `FType* Ptr;` and `const FType& Ref;` — `*`/`&` bind to the type.72- No variable shadowing across scopes.7374Switch statements must have an explicit `default:` branch and document intentional fall-through75with `// falls through`.7677Full formatting rules, switch style, and namespace rules:78[references/formatting-and-includes.md](references/formatting-and-includes.md).7980## Language conventions8182- **`nullptr`** — never `NULL` or `0` for pointers.83- **`override`** on every overriding virtual. Add `final` where the class or function should84 not be further overridden.85- **`const` correctness** — const member functions for non-mutating methods; `const&` for86 non-trivial parameters not being copied; never const a by-value return.87- **`TEXT("...")`** around every string literal that constructs an `FString` or `FName`.88- **`enum class`** over plain enums; back with `uint8` if exposed to Blueprints. Values are89 PascalCase. Use `ENUM_CLASS_FLAGS(EFoo)` for bitfield enums with a `None = 0` sentinel.90- **Engine containers** (`TArray`, `TMap`, `TSet`, `FString`, `FName`) over `std::` equivalents91 in engine-facing code.92- **`auto`** only where the type is either a lambda, a verbose iterator, or genuinely93 indiscernible from context. Always apply `const`, `&`, or `*` explicitly with `auto`.94- **Range-based for** is preferred. For `TMap`, iterate as `for (TPair<K,V>& Kvp : Map)`.95- **Move semantics** — use `MoveTemp(X)` (UE's `std::move`) when transferring ownership of96 containers or `FString` into a member or return.97- **Lambdas** — prefer explicit captures over `[=]` or `[&]`. Captured `UObject*` pointers98 are invisible to the GC. Use `CreateWeakLambda` / `BindWeakLambda` for deferred lambdas.99- **UObjects via pointer** — pass by pointer, not reference. Null is the signal for "absent".100- Portable integer types: `int32`, `uint32`, `uint8`, `float`, `double`, `TCHAR`; avoid bare101 `int` in serialized or replicated data.102103## Headers and includes104105### Header structure (in order)106107```cpp108// Copyright Epic Games, Inc. All Rights Reserved.109110#pragma once111112#include "CoreMinimal.h" // 1. CoreMinimal (or fine-grained core headers)113#include "GameFramework/Actor.h" // 2. Engine / module headers this type needs114#include "MyActor.generated.h" // 3. generated.h — ALWAYS LAST115```116117### Source file structure118119```cpp120#include "MyActor.h" // matching header first121#include "Components/StaticMeshComponent.h" // then any implementation deps122```123124- **`#pragma once`** at the top of every header (all target compilers support it).125- **`generated.h` must be the last include** — UHT requires it. Missing it or putting it in126 the middle causes broken generated code.127- **IWYU** (Include What You Use) — include every header you directly depend on; do not rely128 on transitive includes through another header.129- **Forward declare** in headers where you only need a pointer or reference. In `.cpp`, include130 the full header. This reduces compile times and dependency coupling.131132```cpp133// Header — forward declare only134class UStaticMeshComponent;135136UCLASS()137class MYGAME_API AMyActor : public AActor138{139 GENERATED_BODY()140 UPROPERTY(VisibleAnywhere) TObjectPtr<UStaticMeshComponent> Mesh;141};142143// Source — full include144#include "Components/StaticMeshComponent.h"145```146147Engine evidence: `Actor.h` lines 5–32 use IWYU-style fine-grained includes ending with148`"Actor.generated.h"` at line 32; `Character.h` lines 5–19 show `CoreMinimal.h` first and149`"Character.generated.h"` at line 19.150151## Reflection style152153Every reflected class or struct needs `GENERATED_BODY()` as its **first** body member. Every154public class in a module needs the module `*_API` export macro:155156```cpp157UCLASS(Blueprintable, BlueprintType, config=Game)158class MYGAME_API AWeapon : public AActor159{160 GENERATED_BODY()161public:162 UFUNCTION(BlueprintCallable, Category="Weapon")163 void Fire();164165 UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Stats",166 meta=(ClampMin="0"))167 float Damage = 25.f;168169protected:170 UPROPERTY(VisibleAnywhere, Category="Components")171 TObjectPtr<UStaticMeshComponent> Mesh;172};173```174175Key rules:176- Always set a `Category` on any `UPROPERTY`/`UFUNCTION` the editor will show. Without it,177 properties land in an uncategorized root group.178- Put `meta=(...)` last in the specifier list.179- Use `TObjectPtr<T>` for `UPROPERTY` members holding `UObject`-derived pointers (UE5+ modern180 form). Raw `T*` still works and appears in older code.181- The `*_API` macro (e.g. `MYGAME_API`, `ENGINE_API`) must appear between `class` and the182 class name for any non-inline public API. UBT expands it to `__declspec(dllexport/import)`.183184See [references/reflection-and-uht.md](references/reflection-and-uht.md) for the full specifier185reference, `USTRUCT`/`UENUM`/`UFUNCTION` details, and common UHT errors.186187## Comments and documentation188189- `//` for inline comments; `/** ... */` JavaDoc-style comments on public API declarations —190 these surface as tooltips for Blueprint-exposed members and in the generated API docs.191- Comment *why*, not *what*. Keep comments accurate and current with the code.192- Class comments describe the problem the class solves. Multi-line method comments document193 purpose, parameter units/ranges, return value, and any `@warning`/`@see`/`@deprecated`.194195```cpp196/** Maximum health this actor can have. Modified by difficulty at BeginPlay. */197UPROPERTY(EditDefaultsOnly, Category="Health", meta=(ClampMin="1"))198float MaxHealth = 100.f;199```200201## Logging and errors202203- Log through a named category with `UE_LOG` (`ue-logging-and-assertions`).204- `check(Condition)` for invariants — aborts in all builds if violated. Never put side effects205 inside a `check`.206- `ensure(Condition)` for recoverable "shouldn't happen" — fires once in non-shipping builds,207 returns bool so you can handle the failure.208- Remove debug prints before submitting.209210## Gotchas211212- **Wrong or missing type prefix** — UHT build error; check U/A/F/E/I/T/S.213- **`generated.h` not last** — UHT mis-generates or fails outright.214- **Missing `GENERATED_BODY()`** — compile errors from undefined generated symbols.215- **Missing `Category`** on editor-exposed properties — unorganized Details panel.216- **`m_` prefix or `snake_case`** — not Unreal style; use PascalCase.217- **Missing `b` on booleans** — style violation; also breaks naming-based tooling.218- **`std::` containers in engine-facing code** — use `TArray`/`TMap`/`FString` instead.219- **Omitting `override`** — silent non-override when a virtual signature drifts.220- **Bare `NULL`/`0` for pointers** — use `nullptr`.221- **No `TEXT()` around string literals** — produces an undesirable narrow-to-wide conversion.222- **`auto` overuse** — hide types from readers; use only for lambdas, verbose iterators, or223 template-context expressions where the type is genuinely unwriteable.224- **`[=]`/`[&]` lambda captures** — UObject pointers captured by `[=]` are invisible to the225 GC; deferred `[&]` lambdas dangle. Use explicit captures and weak wrappers.226227## References and source material228229Engine source (UE 5.8, under `Engine/Source/`):230- `Runtime/Engine/Classes/GameFramework/Actor.h`:281–282, 288, 306, 593, 891, 1019, 1024231- `Runtime/Engine/Classes/GameFramework/Character.h`:3, 5, 19, 337–338232- `Runtime/Engine/Classes/Components/ActorComponent.h`:3, 23, 27–38, 159–162, 177, 340233- `Runtime/Engine/Classes/Engine/EngineTypes.h`:62, 75234- `Runtime/Engine/Classes/Interfaces/Interface_AssetUserData.h`:3, 16–22235- `Runtime/CoreUObject/Public/UObject/Object.h`:97–100, 106, 129236- `Runtime/Core/Public/Containers/Array.h`:767237- `Runtime/Core/Public/Windows/WindowsPlatform.h`:209–210238- `Runtime/Core/Public/HAL/Platform.h`:1063–1065239240Official docs (UE 5.8):241- Epic C++ Coding Standard:242 <https://dev.epicgames.com/documentation/unreal-engine/epic-cplusplus-coding-standard-for-unreal-engine>243244Deep-dive references in this skill:245- [references/naming-conventions.md](references/naming-conventions.md) — all prefix rules,246 PascalCase details, boolean/enum/function/macro naming, interface pairing.247- [references/formatting-and-includes.md](references/formatting-and-includes.md) — Allman248 braces, tabs, switch style, const correctness detail, `#pragma once`, include order, IWYU,249 forward declarations, API export macros.250- [references/reflection-and-uht.md](references/reflection-and-uht.md) — `UCLASS`/`USTRUCT`/251 `UENUM`/`UPROPERTY`/`UFUNCTION` specifier reference, `TObjectPtr`, `GENERATED_BODY()`,252 and common UHT errors.