RealDocs

Event Execution Order

Complete reference for the order in which Unreal Engine calls lifecycle events, tick functions, and callbacks. Understanding this order is critical for avoiding init-order bugs, race conditions, and the classic "why is this pointer null in BeginPlay" problem.

Your override
Key event (most commonly used)
Engine-internal
Teardown / destruction

1. Actor Lifecycle (The Big Picture)

Every AActor goes through a fixed sequence from construction to garbage collection. Components follow a parallel but interleaved order. The diagram below shows the full path for a spawned actor (via SpawnActor). Level-placed actors follow a similar path but use PostLoad instead of PostActorCreated.

Construction
Constructor (CDO creation)
C++ constructor runs on the Class Default Object at startup. Do NOT spawn actors or access the world here.
PostInitProperties()
Called after all UProperties are initialized. Safe to set defaults.
PostActorCreated() — spawned actors only
Called once after SpawnActor. Level-placed actors get PostLoad() instead.
OnConstruction(Transform) — Construction Script
Runs in editor and at runtime. Can be called multiple times in editor. Keep it idempotent.
Registration
UActorComponent::OnRegister()
Component is registered with the world. Render/physics state created after this.
UActorComponent::InitializeComponent()
Only called if bWantsInitializeComponent is true.
AActor::PreInitializeComponents()
AActor::PostInitializeComponents()
All components are registered and initialized. First safe point to access other components reliably.
Gameplay Start
AActor::BeginPlay()
UActorComponent::BeginPlay()
World is fully set up. Safe to access other actors, run gameplay logic, start timers.
Gameplay Loop
AActor::Tick(DeltaTime)
UActorComponent::TickComponent(DeltaTime)
Runs every frame (or at a set interval). Tick group determines ordering relative to physics.
Teardown
AActor::EndPlay(Reason)
UActorComponent::EndPlay(Reason)
UActorComponent::OnUnregister()
UObject::BeginDestroy()
UObject::FinishDestroy()
GC runs asynchronously. Never access destroyed objects — use weak pointers or IsValid().

2. Construction & Initialization

The #1 UE beginner mistake: putting gameplay logic in the C++ constructor. The constructor runs on the Class Default Object (CDO) before any world exists. You cannot access GetWorld(), spawn actors, or set timers here. Use BeginPlay() for gameplay init.

What belongs where

Event Use for Safe to access
Constructor CreateDefaultSubobject, set defaults, StructureScriptConfig CDO properties only. No world, no other actors.
PostInitProperties Adjust properties after serialization UProperties initialized. No components registered yet.
PostActorCreated One-time setup after spawn (not level load) Actor exists in world, but components may not be initialized.
OnConstruction Data-driven setup, procedural generation Transform is set. Runs in editor too — keep idempotent.
PostInitializeComponents Cross-component wiring, caching references All components registered and initialized.
BeginPlay Gameplay init, timers, bindings, finding other actors Everything. World is fully set up.

Spawned vs Level-Placed Actors

Spawned (SpawnActor)
  1. Constructor
  2. PostInitProperties
  3. PostActorCreated
  4. OnConstruction
  5. Components register
  6. PostInitializeComponents
  7. BeginPlay
Level-Placed (loaded from map)
  1. Constructor
  2. PostInitProperties
  3. PostLoad
  4. OnConstruction (editor only)
  5. Components register
  6. PostInitializeComponents
  7. BeginPlay
Level-placed actors: OnConstruction does not run again at runtime for actors already placed in a level — it already ran in the editor when the level was saved. Only PostLoad and onwards run at runtime.

3. BeginPlay

BeginPlay is the most commonly overridden lifecycle event. It fires when gameplay starts (or when an actor is spawned during gameplay). The call order is:

AActor::DispatchBeginPlay()
Engine calls this — triggers the chain below.
AActor::BeginPlay()
Your actor override. Call Super::BeginPlay() first.
UActorComponent::BeginPlay() — for each registered component
Components get BeginPlay after the owning actor.
Order between actors is NOT guaranteed. If Actor A depends on Actor B being initialized, do not rely on BeginPlay order. Use PostInitializeComponents for the earliest reliable cross-actor wiring, or defer with a timer / delegate.

When does BeginPlay fire?

  • Level load: After all actors in the level have run through construction and registration
  • Runtime spawn: Immediately after PostInitializeComponents (same frame as SpawnActor call)
  • Streaming sub-levels: When the sub-level becomes visible, actors in it get BeginPlay
  • PIE (Play In Editor): Fires on editor-to-PIE transition for all level-placed actors

4. Per-Frame Tick Order

Each frame, the engine runs through a fixed sequence of phases. Tick functions fire within specific tick groups that determine their position relative to physics.

Frame Start
GEngine->Tick()
Engine-level frame start. World ticking begins.
Input Processing
PlayerController receives input. Enhanced Input actions evaluated.
WorldTick: Pre-Physics
TG_PrePhysics Actors & Components Tick
Default tick group. Most gameplay logic runs here.
Start Physics (async)
TG_DuringPhysics Actors & Components Tick
Runs in parallel with physics. No physics results yet.
End Physics / Wait for Physics
Physics results available from this point. Overlap/hit events fire.
TG_PostPhysics Actors & Components Tick
Use this for logic that depends on physics results from this frame.
Animation Evaluation
Anim Blueprints, Montages, skeletal mesh pose update.
TG_PostUpdateWork Actors & Components Tick
Runs after animation. Good for cameras, IK adjustments, final transforms.
Deferred Spawn / Destroy Processing
Actors queued for spawn or destroy are processed.
FTimerManager: Fire Timers
SetTimer callbacks fire here, after all tick groups.
Latent Action Update
Blueprint Delay nodes, AI latent actions resume.
Camera Manager Update
Rendering: Game Thread Submission
Send scene proxies and draw commands to the render thread.

5. Tick Groups

Every tickable actor and component belongs to a tick group set via PrimaryActorTick.TickGroup or PrimaryComponentTick.TickGroup. The group controls when the tick fires relative to physics.

Tick Group When Best for
TG_PrePhysics Before physics simulation Most gameplay: movement input, AI decisions, ability activation. This is the default.
TG_DuringPhysics Parallel with physics Work that doesn't read or write physics state. Rarely used.
TG_PostPhysics After physics, before animation Responding to collision results, adjusting positions after physics.
TG_PostUpdateWork After animation evaluation Camera adjustments, IK fixups, anything that needs final bone transforms.

Setting tick groups in C++

// In constructor
PrimaryActorTick.TickGroup = TG_PostPhysics;

// For a component
PrimaryComponentTick.TickGroup = TG_PostUpdateWork;

// Tick dependencies — ensure ActorB ticks after ActorA
ActorB->PrimaryActorTick.AddPrerequisite(ActorA, ActorA->PrimaryActorTick);
Tick dependencies let you enforce ordering within a tick group. Use AddPrerequisite to guarantee one actor ticks before another, without moving them to different groups.

6. Timers & Latent Actions

Timers and latent actions run after all tick groups have completed, but still within the same frame.

Mechanism Fires when Notes
SetTimer After all tick groups, in timer manager update Executes on the game thread. Cleared on EndPlay.
SetTimerForNextTick Timer update of the next frame Useful for deferring work by one frame.
Delay (Blueprint) Latent action update, after timers Blueprint Delay node uses the latent action system.
AI MoveTo / latent tasks Latent action update Behavior Tree tasks and AI latent moves update here.

7. Input Processing

Input is processed early in the frame, before any tick groups run.

Platform: Poll hardware input
PlayerInput::ProcessInputStack()
Raw input mapped to input actions via Input Mapping Context (Enhanced Input) or legacy InputComponent bindings.
Input Action Callbacks / Axis Mappings Fire
Your IA_Jump, IA_Move, etc. callbacks trigger here.
Tick groups begin (TG_PrePhysics...)
Enhanced Input actions fire before Tick. If you set a flag in an input callback and read it in Tick, the flag will always be set by the time Tick runs in the same frame. This is reliable.

8. Physics, Overlaps & Hits

Physics simulation runs between TG_PrePhysics and TG_PostPhysics. Overlap and hit events fire after physics completes.

TG_PrePhysics ticks complete
Physics Simulation Step (Chaos / PhysX)
OnComponentBeginOverlap / OnComponentEndOverlap
OnComponentHit
NotifyActorBeginOverlap / NotifyActorEndOverlap
NotifyHit
Component-level delegates fire before actor-level virtual functions.
TG_PostPhysics ticks begin
Movement component sweeps are different. UCharacterMovementComponent performs its own sweeps during TG_PrePhysics (in its tick). Overlap/hit events from movement sweeps fire immediately during that tick, not after the physics step. This is why you can get overlap events before physics runs.

9. Animation Evaluation

Animation evaluation runs after TG_PostPhysics and before TG_PostUpdateWork.

TG_PostPhysics ticks complete
UAnimInstance::NativeUpdateAnimation(DeltaSeconds)
C++ animation update. Set anim variables here.
UAnimInstance::BlueprintUpdateAnimation(DeltaSeconds)
Blueprint Event Graph update. Runs after the C++ update.
Evaluate Anim Graph
State machines, blend spaces, montages evaluated. Final pose computed.
AnimNotify / AnimNotifyState events
Notifies fire based on the evaluated anim position.
SkeletalMeshComponent: update bone transforms
TG_PostUpdateWork ticks begin

10. Game Framework Initialization

When a level loads and a game session starts, the game framework objects are created in a specific order. Understanding this is critical for multiplayer and game mode logic.

Level Load
UGameInstance::Init()
Created once, persists across level transitions. Initialize persistent systems here.
AGameModeBase spawned — server only
AGameModeBase::InitGame()
Called before any players join. Set up game rules here.
AGameStateBase spawned
Replicated to all clients. Holds shared game state.
Player Join
AGameModeBase::PreLogin() — server, multiplayer only
Validate the player. Return an error string to reject.
AGameModeBase::Login()
Creates and returns the PlayerController.
APlayerController spawned
APlayerState spawned
AGameModeBase::PostLogin(NewPlayer)
Player is fully connected. Safe to initialize player-specific state.
AGameModeBase::HandleStartingNewPlayer(NewPlayer)
AGameModeBase::RestartPlayer(NewPlayer)
Finds a PlayerStart and spawns the Pawn. Calls Possess().

11. Pawn Possession

When a Controller possesses a Pawn, the following sequence fires:

AController::Possess(NewPawn)
APawn::UnPossessed() — on old pawn, if any
APawn::PossessedBy(NewController)
Called on the new pawn. Server-side. Set up server state here.
APawn::SetupPlayerInputComponent(InputComponent)
Only for player-controlled pawns. Bind input actions here.
APawn::OnRep_Controller() — clients, replicated
Client-side notification that the controller has changed.
AController::OnPossess(PawnToPossess)
Called on the controller after possession is complete.
Input binding timing: SetupPlayerInputComponent is called during Possess, which happens after BeginPlay. If you need input bindings earlier, you're likely trying to bind too soon. The Pawn must be possessed first.

12. Replication (Multiplayer)

In multiplayer, the server sends replicated properties to clients. Understanding when OnRep callbacks fire relative to other events is essential.

Server → Client replication order

Server: Actor ticks, gameplay modifies replicated properties
Server: Net driver collects dirty properties
Happens at the net update frequency, NOT every tick.
Client: Receive property updates (bunch)
Client: OnRep_PropertyName() callbacks fire
Fire in the order properties are defined in GetLifetimeReplicatedProps. May fire multiple frames after the server change.
Client: Normal tick continues
OnRep timing is unpredictable. OnRep callbacks fire when the network packet arrives, which can be any point in the frame. Do not assume they fire before or after Tick. Also, OnRep does NOT fire on the server — if you need server-side notification, set the value via a setter function that handles both sides.

Client-spawned replicated actors

When a replicated actor arrives on the client, the lifecycle is compressed: PostInitializeComponents → initial OnRep callbacks → BeginPlay. Replicated properties set before spawn are available in BeginPlay on the client (OnRep fires first).

13. EndPlay & Destruction

AActor::EndPlay(EEndPlayReason)
Called when actor is removed from world. Clean up timers, delegates, bindings here.
UActorComponent::EndPlay(EEndPlayReason)
UActorComponent::OnUnregister()
AActor::Destroyed()
Legacy callback. Prefer EndPlay for cleanup.
UObject::BeginDestroy()
GC has claimed the object. Do not access from other objects after this.
UObject::FinishDestroy()
Final cleanup. Memory freed.

EndPlay reasons

EEndPlayReason Triggered by
Destroyed Explicit DestroyActor() call
LevelTransition Seamless or hard travel to another map
EndPlayInEditor Stopping PIE session
RemovedFromWorld Streaming sub-level unloaded
Quit Application exit

14. Common Gotchas

"Pointer is null in BeginPlay"

You're referencing another actor that hasn't had its BeginPlay called yet. Actor BeginPlay order across different actors is not deterministic. Use PostInitializeComponents for cross-actor references, or defer the lookup with SetTimerForNextTick.

"Component is null in constructor"

You used FindComponentByClass in the constructor. Components from Blueprint (added in editor) aren't available until after PostInitializeComponents. Only components created with CreateDefaultSubobject in the same constructor are available.

"OnRep fires before BeginPlay on client"

This is by design for initially replicated actors. Properties set on the server before spawn arrive on the client and trigger OnRep before BeginPlay. This lets BeginPlay see the correct initial state. Guard your OnRep functions against uninitialized state.

"Timer callback fires on a destroyed actor"

Timers set with SetTimer on a UObject are automatically cleared when the object is destroyed. But raw function pointers or lambdas that capture this can outlive the object. Always use the FTimerDelegate form and clear timers in EndPlay.

"Overlap events fire during movement, not after physics"

UCharacterMovementComponent performs sweeps during its tick (TG_PrePhysics). Overlaps from character movement fire immediately, before the physics step. Overlaps from physics simulation (rigid bodies, projectiles) fire after physics. Don't assume all overlaps arrive at the same time.

"Construction Script runs twice in editor"

OnConstruction re-runs whenever you move an actor in the editor, change a property, or recompile the Blueprint. It can run many times. Never put one-time initialization here — it must be idempotent (safe to run repeatedly with the same result).