Start vs Awake in Unity

In Unity by John FrenchUpdated 24 Comments

When working with scripts in Unity, there are a number of special event functions that get called automatically by the engine at predetermined times.

Even if you’re very new to Unity, it’s likely that you’ve seen these automatic functions being used before.

Start and Update, which are added to new scripts by default, are common examples of such functions.

But they’re not the only ones.

In this post, I’ll be exploring two of the most well-used event functions in detail.

Start, which you will likely already be familiar with, and Awake, which may be new to you.

So…

What’s the difference between Start and Awake?

Start and Awake work in similar ways except that Awake is called first and, unlike Start, will be called even if the script component is disabled.

Using Start and Awake together is useful for separating initialisation tasks into two steps. For example, a script’s self-initialisation (e.g. creating component references and initialising variables) can be done in Awake before another script attempts to access and use that data in Start, avoiding errors.

In this post, I’ll be exploring the differences between Start and Awake in more detail so that you know exactly how to use them in your project.

Here’s what you’ll learn on this page

Let’s get started.

Unity’s order of event functions visualised

There are many event functions that take place when an application starts, runs and stops.

Unity calls these events in a specific order:

Unity Event Function Execution Order Visualised

Unity calls special ‘event functions’ in a specific order – this is it.

In this post, I’ll be focussing on the event functions used for initialisation (Awake, On Enable and Start). But you can find a full list of every event function (there are a lot of them) in Unity’s documentation here and an in-depth execution order reference here.

Start vs Awake

In Unity, you will often need to set up variables or make references to other game objects from a script before the game begins.

Even if you’re very new to Unity, you will probably have already seen one initialisation function before… Start.

// Start is called before the first frame update
void Start()
    {
        // Use this for initialisation
    }

If it looks familiar it’s because, along with Update, it’s added to every script by default.

Because of this, it’s probably where you are most likely to have added initialisation code or used it to set up variables and make references to other objects and components.

But there is another function, Awake, that may also come in useful.

How to use Awake

void Awake()
    {
        // Awake is called even if the script is disabled. 
    }

Awake is called when the script is first loaded, or when an object it is attached to is instantiated.

It only gets called once on each script, and only after other objects are initialised.

This means that it is safe to create references to other game objects and components in Awake.

Which is actually a good way to use it, to create initial references between scripts and components that will be needed later on.

However…

You may run into errors if you try to use code in an Awake function that relies on code in another script’s Awake function.

This is because every object’s Awake function is called randomly, meaning you cannot guarantee that one object’s Awake function will be called before another or that any references you create in Awake will be ready to use by other scripts in Awake as well.

For example, consider two different objects getting references to each others’ scripts and components…

In Awake, Object A gets a reference to one of its own components while Object B gets a reference to Object A.

Object A

public class ObjectA : MonoBehaviour
{
  public Reference myReference;

  void Awake()
  {
    myReference = gameObject.GetComponent<Reference>();
  }
}

Object B

public class ObjectB : MonoBehaviour
{
  public ObjectA objA;

  void Awake()
  {
    objA = GameObject.FindWithTag("ObjectA").GetComponent<ObjectA>();
  }
}

Awake happens after objects are created. So, even though it’s the first event function called, both of the game objects and their components already exist and there are no errors.

So far so good.

However…

If Object B also tries to access Object A‘s component reference, it doesn’t work, causing an error.

public class ObjectB : MonoBehaviour
{
  public ObjectA objA;

  void Awake()
  {
    objA = GameObject.FindWithTag("ObjectA").GetComponent<ObjectA>();
    Debug.Log(objA.myReference.message);
  }
}

This can happen even if Object A‘s Awake function is called before Object B.

Null Reference Exception when using Awake in Unity

Trying to use a reference when it’s not there causes an error.

This is simply because Object A hasn’t made the reference to its own component yet and Object B is trying to access it.

So what’s the solution?

You already know it…

How to use Start

Start is called once, before any Update methods and after Awake. It works in much the same way as Awake, with a few key differences.

  • Unlike Awake, Start will not be called if the script is disabled
  • Start can be called as a coroutine

This means that code that is placed in Start can be delayed.

How to delay Start in Unity

Start only gets called on a script if the component is enabled.

This means that you can manually delay Start from being executed by keeping the script disabled until you need it.

Start can also be called as a coroutine.

This means that you can delay operations called in Start to take place after a predetermined delay. For example, 5 seconds.

Simply change the default ‘void’ return type to ‘IEnumerator’. Like this:

IEnumerator Start()
    {
        yield return new WaitForSeconds(5);
        // Do something after 5 seconds
    }

Late Start in Unity

While manual methods of delaying Start can work well, there may be times when staging code in this way isn’t suitable.

Luckily, it’s possible to manage the execution order of specific scripts so that their Start function is called earlier or later than other Start functions that are called at the same time.

This works by adding a script to the Script Execution Order, which is a list, found in Project Settings, that will prioritise certain scripts over all others during an event function.

While managing the execution order of Start can be useful, the most powerful way to use Start is with Awake.

Using Start and Awake together in Unity

In many cases, you may be able to do all of your initialisation in only Start or Awake, which is perfectly fine if it works for you.

However,

Using Start and Awake together offers you two initialisation steps, one after the other.

This means you can separate the code that creates references between objects and components from the code that actually uses them to do something, which makes it easier to avoid null reference errors when initialising scripts.

And while there’s no one rule for how to do this, it can help to make a decision on early on about what kind of code will take place in Start and what kind of code will happen in Awake.

For example…

One approach is to use Awake to initialise an object’s own references and variables, (e.g. creating the connections between the object and its own components) while then using Start to use or create references to other objects and their components.

This approach prevents a script from trying to use to a reference that doesn’t exist yet, such as in the example earlier or when using functions that don’t work properly when called from Awake, such as trying to call Set Float to change an Audio Mixer parameter (it just doesn’t work).

Exactly how useful this will be for you depends entirely on your project and how it is structured however, generally, it’s good practice to use both Awake and Start when initialising scripts in order to avoid errors.

Lastly, there is one more initialisation function that’s worth mentioning and that works in a similar way to Start, On Enable.

On Enable vs Start in Unity

On Enable and Start both get called when the script component is enabled, whether that’s manually from a script or automatically at the beginning of the game, with On Enable getting called first.

So what’s the difference between On Enable and Start? And which should you use?

While Start will only ever be called once, On Enable is called every time the script component, or the object it’s attached to, is enabled.

Because of this On Enable isn’t usually suitable for initialisation tasks that only need to happen once.

Unless… that’s actually the behaviour you want.

For example, when object pooling.

Object pooling is a technique to avoid repeatedly destroying and instantiating objects that are frequently re-used, such as projectiles and enemies, by simply disabling and re-enabling them again in a new position. This is often more efficient, saving CPU and memory.

When using an Object Pool, code that you might normally put in Start can, instead, be placed in On Enable. For example, setting the enemy’s health to its starting value in On Enable will mean that the enemy gets ‘set-up’ correctly every time it’s re-enabled.

Now it’s your turn

Now I want to hear from you.

How are you using Start and Awake? Do you follow a simple guideline to separate what code goes in which function?

Or maybe you’re only using one of them. If so, how’s that working out for you?

Whatever it is, let me know by leaving a comment below.

Image attribution

Abstract photo created by starline – www.freepik.com

John French profile picture

by John French

Game audio professional and a keen amateur developer.

Get Game Development Tips, Straight to Your inbox

Get helpful tips & tricks and master game development basics the easy way, with deep-dive tutorials and guides.

How this content was created

This article was written using first-hand research and experience, without the use of AI. For more information on how Game Dev Beginner articles are written, see my writing policy.

Comments

  1. So, as I understand it, when an object is instantiated by another script, the new object’s Awake() executes before control is returned to the instantiating script. I have a script that depends on this and it was working fine until it suddenly wasn’t. Now, when I step through it in the debugger, the instantiating script instantiates the object, then the new script goes through all the variable declarations and… returns to the instantiating script, which goes on its merry way. Has this behavior been changed recently? I don’t think I updated Unity.

  2. Never mind. Awake() wasn’t triggering because I was instantiating an un-enabled object.

  3. No way!!! You can use IEnumerator Start() to run it as a Coroutine? Now I gotta try that.

  4. Great resumé! Thanks a lot from an experienced VB programmer moving towards Unity and C#. Crisp and Clear.

  5. Only a minor thing, maybe, but shouldn’t the second picture example of the ‘ObjectB’ script be showing an awake method and not start? As start would be able to get the reference, assuming ObjectA was not disabled, right?

    Either way, love receiving these helpful articles through the newsletter. Stay safe!

  6. I subscribe to one newsletter. One. This one.

    As allways John chooses his words well, gets to the point without leving anything out.

    Thank you.

  7. Thanks for posting this! I’ve a question, if you cache a component (like Animator) in Awake or Start then disable the object what happens when you later enable it?

    1. Author

      Off the top of my head, that reference should still be intact, so it’ll be there when the object is re-enabled.

  8. This is great, thanks John! I really like the way you explain these topics.

  9. Is it failing because the type of T is objA instead of ObjectA?

    objA = GameObject.FindWithTag(“ObjectA”).GetComponent();

    1. Author

      Well spotted, I’ve corrected that typo but that’s not why it was failing.

  10. Don’t know if you read comments on your older posts, but this helped me fix a problem (I had one object being created from Start and another object trying to call it from Start at the same time) that was ruining my Saturday, thanks!

    1. Author

      I do! And great to hear it helped you with your problem!

  11. Hi, I wonder if you might deep dive into OnEnable a bit more? Which, btw, is On Enable in a number of places in this article so might not be SEO’ing very well. The reason is that so many videos and articles show examples with it only being enabled once and manually turned on/off. If you’re doing it programmatically, I keep finding it being a lot more ropey as to whether it’s even called at all when you do enabled = true. I might be creating weird scenarios, like it turning itself on/off, in events/update loop, whether the gameObject it’s attached to is on/off, etc. Appreciate your posts and the level of depth you go into on them.

    1. Author

      Thanks for the feedback, I’ll make a note to expand on this in the article.

Leave a Comment