Skip to main content
Components follow a well-defined lifecycle. Understanding when each method is called lets you write initialization, teardown, and per-frame logic correctly without subtle ordering bugs.

Lifecycle overview

1

OnAwake

Called once, the first time the component becomes active. This happens during the CallbackBatch that processes the component’s first enable — typically immediately after the containing scene tick starts or when the GameObject is first created in a running scene.Use OnAwake for one-time initialization that should happen before the component is enabled (caching references, creating objects, setting initial state).
protected override void OnAwake()
{
    // Runs once, ever. Safe to cache references here.
    _rb = GetComponent<Rigidbody>();
    Log.Info( $"{GameObject.Name} awoke" );
}
OnAwake is only called if ShouldExecute is true (see below). Interpolation is disabled during this call so that transform changes take effect immediately.
2

OnEnabled

Called every time the component transitions from inactive to active — that includes immediately after OnAwake on first enable, and again each time the component or any ancestor GameObject is re-enabled.
protected override void OnEnabled()
{
    // Register listeners, subscribe to events, spawn effects
    Scene.GetAllComponents<EventBus>()
         .FirstOrDefault()
         ?.Subscribe( OnGameEvent );
}
3

OnStart

Called once immediately before the component’s first OnUpdate (or OnFixedUpdate if that runs first). This lets you perform setup that requires all other components in the scene to have already run their OnAwake and OnEnabled.
protected override void OnStart()
{
    // All siblings have OnAwake by now — safe to cross-reference them
    _target = Scene.GetAllComponents<PlayerController>().FirstOrDefault();
}
Prefer OnStart over OnAwake when your setup depends on other components existing. OnAwake fires very early and other components in the same batch may not have awoken yet.
4

OnUpdate

Called every frame while the component is active. Time.Delta is the time in seconds since the last frame.
protected override void OnUpdate()
{
    Transform.LocalRotation *= Rotation.FromYaw( 90f * Time.Delta );
}
OnUpdate does not run on a dedicated server by default. If your component implements DontExecuteOnServer, it is excluded entirely. For server-side logic, use OnFixedUpdate or check Application.IsServer.
5

OnFixedUpdate

Called at a fixed interval tied to the physics tick rate (configured in Project Settings → Physics). Time.Delta inside OnFixedUpdate is the fixed timestep, not the variable frame delta.Use OnFixedUpdate for anything that must stay in sync with physics: movement via Rigidbody, collision response, or deterministic simulation.
protected override void OnFixedUpdate()
{
    // Time.Delta here is the fixed physics timestep
    _rb.ApplyForce( Vector3.Up * 100f * Time.Delta );
}
6

OnPreRender

Called once per frame just before the scene is rendered. Not called on dedicated servers. Use this to update mesh bones, synchronize visual state, or push data to the render world.
protected override void OnPreRender()
{
    // Update a SceneObject's transform to match the GameObject
    _sceneObject.Transform = Transform.World;
}
7

OnDisabled

Called every time the component transitions from active to inactive — including when the GameObject is disabled, when the component’s Enabled is set to false, and just before OnDestroy.
protected override void OnDisabled()
{
    // Unsubscribe from events, despawn visual effects
    Scene.GetAllComponents<EventBus>()
         .FirstOrDefault()
         ?.Unsubscribe( OnGameEvent );
}
8

OnDestroy

Called once when the component is permanently removed — either because Destroy() was called on it, or because its parent GameObject was destroyed. After this call the component is no longer valid.
protected override void OnDestroy()
{
    // Clean up native resources, pooled objects, etc.
    _particleEffect?.Destroy();
}
After OnDestroy, GameObject is set to null internally. Do not store references to the component after destruction — use IsValid() to guard any deferred callbacks.

Additional callbacks

OnValidate

Called immediately after deserializing from JSON (scene or prefab load) and whenever a [Property] is changed in the editor inspector. Use it to clamp values, rebuild derived state, or log warnings when configuration is invalid.
protected override void OnValidate()
{
    MaxHealth  = Math.Max( 1f, MaxHealth );
    // Recalculate derived values when a property changes in the inspector
    _halfHealth = MaxHealth * 0.5f;
}

OnRefresh

Called after the component’s state is updated from a network snapshot. Use it to react to authoritative values arriving from the host.
protected override void OnRefresh()
{
    // Server just pushed new health value — update the health bar
    _healthBar.SetFraction( CurrentHealth / MaxHealth );
}

OnParentChanged

Called when the component’s GameObject is re-parented. Both the old and new parent are provided.
protected override void OnParentChanged( GameObject oldParent, GameObject newParent )
{
    Log.Info( $"Moved from {oldParent?.Name} to {newParent?.Name}" );
    // Update network root, tag cache, etc.
}

OnTagsChanged

Called when the GameObject’s tag set changes.
protected override void OnTagsChanged()
{
    _isBoss = Tags.Has( "boss" );
}

The ShouldExecute rules

Not every component executes in every context. Before calling OnAwake, OnEnabled, OnUpdate, and OnFixedUpdate, the engine checks a private ShouldExecute gate:
ConditionResult
Scene is a PrefabCacheSceneNever executes
Scene is nullNever executes
Scene is an editor preview scene (IsEditor == true) and the component does not implement ExecuteInEditorNever executes
Application.IsDedicatedServer == true and the component implements DontExecuteOnServerNever executes
All other casesExecutes normally
// This component runs in editor preview scenes
public sealed class MyEditorTool : Component, ExecuteInEditor
{
    protected override void OnUpdate()
    {
        // Called in editor scene ticks
    }
}

// This component is skipped on dedicated servers
public sealed class ParticleSpawner : Component, DontExecuteOnServer
{
    protected override void OnUpdate()
    {
        // Not called when running as a dedicated server
    }
}

Order summary

Component created / enabled


     OnAwake()          ← once, ever


     OnEnabled()        ← each time active transitions false → true

         ▼  (first tick)
     OnStart()          ← once, before the first Update

    ┌────┴─────────────────────────────────┐
    │  per-physics-tick   │  per-frame     │
    ▼                     ▼                │
OnFixedUpdate()       OnUpdate()          │
                          │               │
                      OnPreRender()       │
    └─────────────────────────────────────┘

         ▼  (on disable)
     OnDisabled()      ← each time active transitions true → false

         ▼  (on destroy)
     OnDestroy()       ← once, ever

Components

How to create components, use [Property], and query the hierarchy

Scenes and GameObjects

The hierarchy that components live inside

Build docs developers (and LLMs) love