The MonoBehaviour Lifecycle: Awake, Start, Update and the Order of Things
Unity never calls your scripts at random; it calls them in a strict sequence of lifecycle methods, and most initialization bugs come from misunderstanding which of those moments a piece of code really belongs to.

A newcomer to Unity writes a script, attaches it to an object, presses Play, and watches something happen. Where the script began running, and why, are questions that seldom arise in the first week. The code simply seems to wake up. Yet behind that apparent spontaneity lies a fixed and rather exacting ceremony, a sequence of calls the engine makes into every MonoBehaviour in a definite order, and a great many of the bugs that later torment the same developer are, at bottom, disagreements with that ceremony.
The methods involved are called event functions, and they have reserved names: Awake, OnEnable, Start, FixedUpdate, Update, LateUpdate, OnDisable, OnDestroy and a number of others. Unity does not require a script to override anything. It inspects each class, notes which of these names are present, and calls them at the appropriate moments, which is why a misspelt Updat or a method named start with a lowercase letter is silently ignored rather than flagged, and why such typos can survive for an astonishingly long time.
Understanding the lifecycle means understanding three things at once: when each function runs, what is guaranteed to exist at that moment, and what is not. The sections that follow take the functions roughly in the order an object experiences them, from the instant it is loaded to the instant it is destroyed, and close with the settings Unity provides for those rare occasions when the default ordering between different scripts is simply not good enough.
Awake and the moment of loading
Awake is the first event function a script receives, and it is called exactly once in the life of a script instance. For objects saved in a scene, it runs while the scene loads; for objects created with Instantiate, it runs immediately, inside the Instantiate call itself, before that call returns. In both cases it is the place for a script to prepare itself: to cache references to its own components, to allocate collections, to set fields that do not depend on any other object being ready.
There is a subtle condition attached to Awake that surprises many people. It is called if the GameObject is active, regardless of whether the component itself is enabled. A script whose checkbox is unticked in the Inspector will still receive Awake, so long as its object is active in the hierarchy. If the object is inactive at load, however, Awake is postponed until the moment the object is first activated, which may be much later or, in the case of an object that is never switched on, never at all.
What Awake does not promise is any order among different objects. When a scene loads, Unity calls Awake on every active object, but it makes no guarantee that the Awake of a GameManager runs before the Awake of a Player that wants to register with it. Code that reaches into another object during Awake and expects it to be initialized is therefore gambling, and the gamble may pay off for months before a change in scene composition reverses the outcome and breaks the build on someone else's machine.
This is also why constructors are a poor substitute. A MonoBehaviour may be constructed by Unity's serialization system at times the developer does not control, sometimes more than once in the editor and not necessarily on the main thread, and most of the engine's API is forbidden there. Awake exists precisely so that a script has a safe, predictable first moment to run its own setup, and seasoned developers treat it as the true beginning of a component's life.
OnEnable and the switch
OnEnable follows Awake almost immediately for each script, and it is called whenever the component becomes both enabled and active. Unlike Awake, it is not a one time event. A script that is disabled and enabled again, or whose GameObject is deactivated and reactivated, receives OnEnable on every return to life. This makes it the natural home for work that must be undone when the script goes quiet, the commonest example being subscription to events raised by other objects or by static systems.
The order for a single script on an active object is Awake, then OnEnable, with nothing in between. A script disabled in the Inspector receives Awake but not OnEnable, which waits until the component is switched on. The pairing matters because it lets a developer divide initialization cleanly: Awake for what should happen once in the object's whole existence, OnEnable for what should happen every time the object comes into play, such as resetting a timer or registering with a manager that keeps a list of active units.
Object pooling depends heavily on this distinction. A pooled projectile is never destroyed; it is deactivated when it strikes something and reactivated when fired again. Its Awake ran once, long ago, when the pool was filled. Its OnEnable runs on every launch, and that is where its speed, lifetime and trail must be reset. Code placed in Start instead would run only on the first firing, and every later projectile would inherit whatever stale state the previous flight had left behind it.
Start and the first frame
Start is called once, shortly before the script's first Update, and only if the script is enabled at that moment. A component that remains disabled never receives Start; if it is enabled later, Start runs then, just before its first Update. The more valuable guarantee concerns timing: for all the objects present when a scene loads, every Awake and OnEnable completes before any Start is called. By the time Start runs, every other object in the scene has at least prepared itself.
That guarantee suggests a simple and dependable division of labour. In Awake, a script sets up only itself. In Start, it reaches out to others, looking up the manager it needs, reading configuration another object has already loaded, subscribing to systems that now certainly exist. Following this rule removes most initialization races without any special settings at all, because the engine itself has drawn a line between preparing oneself and introducing oneself, and the line holds for every object loaded with the scene.
Objects created during play complicate the picture slightly. An object instantiated in the middle of a frame receives Awake and OnEnable at once, but its Start is deferred until before its first Update, which normally falls on the following frame. Code that instantiates an object and immediately calls a method that relies on Start having run will find the object half prepared. Start may also be declared as a coroutine that returns IEnumerator, allowing it to wait several frames or seconds before finishing its work.
The loop that repeats
Once an object is initialized, it enters the repeating portion of the lifecycle. FixedUpdate runs on the fixed timestep used by the physics engine, which by default is 0.02 seconds, or fifty times per simulated second; depending on the frame rate, it may run several times in one rendered frame or not at all. Immediately after the FixedUpdate calls, Unity advances the physics simulation, and collision and trigger callbacks such as OnCollisionEnter and OnTriggerEnter are delivered as part of that physics step.
Update runs once per rendered frame, after the frame's physics work and after input has been gathered. It is where most gameplay logic lives: reading the player's intentions, advancing timers, deciding what an enemy should do next. Coroutines that yield null resume just after Update, which is why they too advance once per frame. Then the engine evaluates animation, and after that LateUpdate is called, a final opportunity for scripts to act once everything else in the frame has moved.
LateUpdate earns its place through ordering alone. A camera that follows a character should move after the character has moved, otherwise it trails one frame behind and jitters. Because LateUpdate runs after every Update, and after the Animator has posed the skeleton, it is the right place for cameras, for aiming adjustments layered over animation, and for anything that must read the final positions of the frame before rendering begins and the image is committed to the screen.
OnDisable, OnDestroy and the end
The lifecycle ends in mirror image. OnDisable is called whenever a component stops being enabled and active: when it is disabled, when its GameObject is deactivated, and also just before the object is destroyed. It is the counterpart of OnEnable, and whatever was subscribed there should be unsubscribed here. A script that adds itself to a static event in OnEnable but forgets to remove itself in OnDisable leaves a reference behind, and the static event will try to call a destroyed object later, with errors that are maddening to trace.
OnDestroy is called once, when the object is destroyed, when its scene is unloaded, or when the application quits. Unity documents one important qualification: OnDestroy is only called on objects that were previously active. An object that sat inactive from load until destruction never received Awake, and it receives no OnDestroy either. Final cleanup belongs here, the release of native resources or the saving of something that must not be lost, though code that depends on other objects still existing should be written defensively.
That caution is justified by quitting and unloading, during which objects are torn down in no promised order. A script whose OnDestroy calls into a manager may find the manager already gone, its fields nulled out, its own OnDestroy already run. Some developers check a flag set in OnApplicationQuit, which arrives before the destruction begins, and skip nonessential work when the whole application is closing. The end of the game, like a fire in a crowded hall, is no place to assume the exits are where they were.
Script Execution Order
Sometimes the guarantees above are not enough. Two managers may both need to finish Awake before anything else runs, or an input reader may need its Update to precede every other script's Update in the same frame. For these cases Unity offers the Script Execution Order settings, found under Project Settings. Scripts listed there are given numeric values; those with lower values run their event functions earlier, those with higher values run later, and unlisted scripts share the default slot at zero.
The same ordering can be expressed in code with the DefaultExecutionOrder attribute, placed above a class with an integer argument. This keeps the priority beside the script it governs and survives copying the file to another project, which the settings panel does not. Either way, the effect applies between scripts rather than between individual objects: all instances of a script with order minus one hundred run their Update before any instance of a script left at the default.
These tools are best used sparingly. Each entry is an invisible dependency that the next reader of the code may not know exists, and a long list of carefully tuned numbers tends to become a fragile structure that nobody dares touch. Most ordering problems dissolve when scripts follow the Awake for self, Start for others discipline, or when dependencies are passed in explicitly rather than discovered. When an explicit order is truly needed, a small number of foundational systems at the front of the list usually suffices.
When an ordering bug does surface, the fastest diagnosis is rarely clever. A Debug.Log placed at the top of each suspect event function, printing the script name and Time.frameCount, turns an invisible sequence into a readable transcript, and the culprit usually announces itself within a few lines: a Start that ran before the object it depended on had been enabled, an OnEnable that fired inside Instantiate while the calling code had not yet set its fields. Reading that transcript is often the moment a developer stops suspecting the engine of caprice and begins to see its rules.


