【Unity】Unity Lifecycle Complete Guide - Awake, Start, and Update Execution Order

Created: 2025-12-07Last updated: 2026-07-13

Learn when and in what order Unity scripts execute. A beginner-friendly, illustrated guide to the roles and differences of key event functions like Awake, Start, Update, FixedUpdate, and LateUpdate.

"The reference I got in Start is suddenly null." "My physics movement is weirdly jittery." Many of the bugs that plague Unity beginners can be avoided simply by knowing when and in what order your scripts run. That sequence is called the "lifecycle."

Unity scripts follow a fixed order of event functions that are called automatically, from an object's birth to its destruction. This article walks through the most important ones—Awake, Start, Update, FixedUpdate, and LateUpdate—with diagrams showing what each is for and when to use which.

Unity's lifecycle as a loop of processes repeating in a fixed order, with a character standing at the center

What You'll Learn

  • The overall lifecycle flow (one-time processing vs. per-frame processing)
  • How to use Awake and Start correctly
  • The differences between Update, FixedUpdate, and LateUpdate, with real examples
  • How to keep these functions from hurting performance

Sponsored

Lifecycle Events Overview

Unity scripts have "event functions" that are automatically called when specific events occur. These functions execute in a defined order, from when an object is loaded into a scene until it's destroyed. The main event functions run in this order:

  1. Initialization

    • Awake(): Called once, immediately after the object is loaded. Runs before any other function.
    • OnEnable(): Called the moment the object becomes active. Unlike Awake, it fires every time the object is re-enabled with SetActive(true).
    • Start(): Called once, just before the first frame's Update.
  2. Physics

    • FixedUpdate(): Called at fixed time intervals. Suited to physics processing.
  3. Game Logic

    • Update(): Called every frame. This is where main game logic and input handling live.
    • LateUpdate(): Called every frame, after all Update functions have run. Used for camera follow logic and the like.
  4. Rendering

    • OnRenderObject() etc.: Processing related to drawing the object.
  5. Teardown

    • OnDisable(): Called the moment the object becomes inactive.
    • OnDestroy(): Called just before the object is destroyed.

Here is the whole flow as a diagram. FixedUpdate, Update, and LateUpdate repeat every frame, while Awake, Start, and OnDestroy run only once per object. The ones to watch are OnEnable and OnDisable: these two fire again and again, every time the object is enabled or disabled (we'll verify this in the hands-on section later).

Flow diagram of Unity's lifecycle execution order: after Awake, OnEnable, and Start, FixedUpdate, Update, and LateUpdate loop every frame, and OnDestroy is called at the end

Note: When multiple objects exist, the order in which their Awake() calls run is not guaranteed. Never assume "A's Awake runs before B's Awake." If you truly need to control the order, you can specify it explicitly under Edit > Project Settings > Script Execution Order.

Sponsored

Key Event Functions in Detail

Initialization: Awake() vs Start()

Both Awake() and Start() are used for initialization, but there's an important difference in when they run.

FunctionExecution TimingPrimary Use
Awake()Immediately after the script instance loads. Always before Start().Getting references to your own components; initialization that doesn't depend on other objects' state.
Start()Just before the first frame's Update(). After Awake().Initialization that assumes other objects' Awake() has already completed.

The crucial point is that, for objects present at scene load, every object's Awake() completes before any object's Start() is called. So when scripts need to pass references to each other, it's safest to acquire references in Awake() and then use them in Start().

That guarantee only covers objects that already exist when the scene loads, though. An object created at runtime with Instantiate() runs its Awake() immediately, right inside that call (we'll see this for ourselves in the hands-on section).

Think of it this way: Awake is when everyone gets themselves ready, and Start is when everyone—now prepared—begins coordinating with each other.

The different roles of Awake and Start: Awake handles your own setup (getting your own components), while Start handles coordination with other objects
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    private Rigidbody rb;
    private GameManager gameManager;

    // Get your own components in Awake
    void Awake()
    {
        rb = GetComponent<Rigidbody>();
        Debug.Log("Awake: Got Rigidbody.");
    }

    // Logic that assumes other objects are initialized goes in Start
    void Start()
    {
        gameManager = FindFirstObjectByType<GameManager>();
        gameManager.RegisterPlayer(this);
        Debug.Log("Start: Registered player with GameManager.");
    }
}

Note: FindObjectOfType<T>() used to be the go-to here, but it's been deprecated since Unity 2023.1 (including Unity 6) in favor of the faster FindFirstObjectByType<T>(). Keep this in mind when following older articles or sample code.

Updates: Update() vs FixedUpdate() vs LateUpdate()

These functions are called every frame, or at a similar frequency, but their purposes are clearly distinct.

FunctionExecution TimingPrimary Use
FixedUpdate()Fixed time intervals (default 0.02 seconds). Independent of frame rate.Physics using Rigidbody (applying forces, etc.).
Update()Every frame. The interval varies with frame rate.Input handling, time-based movement, general game logic.
LateUpdate()After all Update() calls complete.Camera follow, character IK (Inverse Kinematics), etc.

The difference is easiest to see on a timeline of when each is called.

Comparison of Update and FixedUpdate call timing: Update fires at uneven, frame-rate-dependent intervals, while FixedUpdate fires at fixed intervals (default 0.02 seconds)

FixedUpdate() is synchronized with the physics engine's update timing, so physics operations like applying forces to a Rigidbody must always happen there. Update(), on the other hand, runs once per frame, making it the right place for input detection, visual updates, and anything else not directly tied to physics. Multiply by Time.deltaTime to keep movement consistent regardless of frame rate fluctuations.

Note: It's not "one Update and one FixedUpdate per frame." At high frame rates, some frames will pass with FixedUpdate() not being called at all; at low frame rates it can run multiple times in a single frame. This is exactly why the standard pattern is "detect input in Update(), apply physics movement in FixedUpdate()"—reading Input.GetKeyDown and the like inside FixedUpdate() can cause you to miss inputs.

Mapping this to real development scenarios: anything that concerns what the player sees and does goes in Update, and anything you hand off to the physics engine goes in FixedUpdate. Remember it that way and you'll rarely go wrong.

Practical examples of Update vs FixedUpdate: Update handles per-frame work like key input detection, camera follow, and UI updates, while FixedUpdate handles Rigidbody physics like applying forces with AddForce

LateUpdate() is for logic that should run after every other object's Update() movement has finished. A classic example: the player character moves in Update(), then the camera follows the player in LateUpdate(). This prevents the camera from stuttering.

using UnityEngine;

public class CameraFollow : MonoBehaviour
{
    public Transform target;
    public Vector3 offset;

    // Update the camera position after the target has finished moving
    void LateUpdate()
    {
        if (target != null)
        {
            transform.position = target.position + offset;
        }
    }
}
Sponsored

Hands-On: Watching the Call Order in Three Cases

Rather than memorizing a table, watching the order in the Console makes it stick for good. Here we observe three situations that come up daily in any genre—enemies in an action game, NPCs in an RPG, bullets in a shooter—all with a single script.

  • Case 1: Scene load—how do objects placed in the scene from the start get initialized?
  • Case 2: SetActive on/off—what gets called when a pause menu opens and closes, or an object is shown and hidden?
  • Case 3: Instantiate at runtime—what happens the instant you spawn a bullet or an enemy?
Comparison of the three lifecycle cases: on scene load everyone's Awake runs before anyone's Start, toggling SetActive fires only OnEnable and OnDisable each time, and Instantiate at runtime runs Awake and OnEnable immediately with Start delayed until before the next Update

The observer script is just this. Attach it to an empty GameObject:

using UnityEngine;

public class LifecycleLogger : MonoBehaviour
{
    void Awake()     { Debug.Log($"{name}: Awake"); }
    void OnEnable()  { Debug.Log($"{name}: OnEnable"); }
    void Start()     { Debug.Log($"{name}: Start"); }
    void OnDisable() { Debug.Log($"{name}: OnDisable"); }
    void OnDestroy() { Debug.Log($"{name}: OnDestroy"); }
}

For Case 1, place two objects with this script in the scene—EnemyA and EnemyB—and press Play. You'll see EnemyA: AwakeEnemyB: Awake → (only after everyone's Awake is done) EnemyA: StartEnemyB: Start. All the Awakes finish before any Start begins.

For Case 2, while the game is running, uncheck EnemyA in the Inspector and check it again. The only log lines are OnDisable and OnEnableAwake and Start fire only the very first time. The classic bug of "I put my re-initialization code in Start, and it never runs when the object comes back" comes from not knowing this difference.

For Case 3, use the following script to spawn a bullet while the game is running:

using UnityEngine;

public class Spawner : MonoBehaviour
{
    [SerializeField] private GameObject bulletPrefab;

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            Debug.Log("--- Before Instantiate ---");
            Instantiate(bulletPrefab);
            Debug.Log("--- After Instantiate ---");
        }
    }
}

The log order is: "Before" → AwakeOnEnable → "After" → (at the top of the next frame) Start. In other words, by the time the Instantiate() line finishes, the new object's Awake has already run—but its Start is delayed until just before the next Update. Code that tries to use the results of the spawned object's Start immediately after spawning it simply won't work. A huge share of spawn-related bugs are born right here.

Two takeaways: the "everyone's Awake, then everyone's Start" guarantee applies at scene load, and OnEnable/OnDisable are the only ones that fire again and again. Verify both with your own eyes once, and you'll diagnose initialization bugs far faster.

Performance Considerations

Update() and FixedUpdate() are called extremely frequently, so heavy processing inside them can seriously hurt your game's overall performance. Watch out for the following:

  • Don't overuse Update(): Anything that doesn't need to run every frame should be moved out of Update(). For logic that only runs when a condition is met, consider event-driven design or coroutines.
  • Cache GetComponent results: Calling GetComponent<T>() inside Update() is very inefficient. Retrieve the components you need once in Awake() or Start() and store (cache) them in variables.
  • Custom update managers: When hundreds or thousands of objects each have their own Update(), the call overhead between Unity's native code and C# can become a problem. In such cases, a singleton class (a custom update manager) that calls each object's update method itself can improve performance.

Bonus: Good to Know for Later

Once you've got the lifecycle down, these topics are the natural next steps. For now, just knowing they exist is enough.

  • There are more event functions: Beyond the ones covered here, there are physics event functions like OnTriggerEnter/OnCollisionEnter, called the instant objects collide. See the OnTrigger and OnCollision article for details.
  • Coroutines excel at time-based logic: For things like "run this in 3 seconds" or "fade out gradually," coroutines are much simpler than hand-rolling timers in Update. See the coroutines article.
  • Update gets expensive at scale: Once you have thousands of objects, the overhead of the Update calls themselves becomes significant. The fix is the technique covered in the custom update manager article.

Summary

Understanding Unity's lifecycle is essential knowledge for every Unity developer, from beginner to professional. Knowing when and why each event function is called lets you write more reliable, better-performing code.

  • Initialization: Get yourself ready in Awake(), then start coordinating with other objects in Start().
  • Updates: Physics goes in FixedUpdate(), input and logic in Update(), follow behavior in LateUpdate().
  • Performance: Avoid heavy processing inside Update() and always cache your components.

Master these fundamentals and take your first step toward efficient Unity development.