Singleton Pattern
Summary
The singleton is a design pattern from the Gang of Four’s Design Patterns catalogue, whose stated intent is to “ensure a class has one instance, and provide a global point of access to it” (as quoted by Nystrom, Game Programming Patterns, “Singleton” chapter). Robert Nystrom points out that this is really two ideas bundled together: restricting a class to a single instance, and making that instance globally reachable. Most code that uses a singleton only wants the second part.
In Unity, a singleton is usually a MonoBehaviour with a static property called Instance. The first copy to wake up stores itself in Instance; any later copy destroys itself; and any script can then write AudioManager.Instance.PlaySfx(clip) without an Inspector reference. Unity’s own patterns guide describes manager-level objects such as a game manager or a file manager as natural candidates, while noting that the singleton is “one of the most maligned design patterns” because its ease of use invites overuse (Unity Technologies, Level Up Your Code with Game Programming Patterns, see source-unity-game-programming-patterns).
Use it sparingly, for a small number of genuinely global services (audio, a persistent game manager, save data), and only once a plain Inspector reference has become impractical. The unity-gamemanager-pattern page shows the singleton applied to a GameManager; this page covers the pattern itself, its risks and its alternatives.
Implementation
A minimal Unity singleton
using UnityEngine;
public class AudioManager : MonoBehaviour
{
public static AudioManager Instance { get; private set; }
[SerializeField] private bool persistAcrossScenes = true;
[SerializeField] private AudioSource sfxSource;
private void Awake()
{
if (Instance != null && Instance != this)
{
Debug.LogWarning($"Duplicate AudioManager on {name} destroyed.", this);
Destroy(gameObject);
return;
}
Instance = this;
if (persistAcrossScenes)
DontDestroyOnLoad(gameObject); // only works on a root GameObject
}
private void OnDestroy()
{
if (Instance == this) Instance = null;
}
public void PlaySfx(AudioClip clip) => sfxSource.PlayOneShot(clip);
}Reading it line by line:
public static AudioManager Instance { get; private set; }is a property that belongs to the class rather than to any object (see csharp-oop-fundamentals onstatic). Anyone can read it; only this class can set it.- The duplicate guard in
Awakekeeps the first instance and destroys any other. Without it, reloading a scene that contains the manager produces two managers, and anything they count is counted twice. DontDestroyOnLoadkeeps the GameObject alive when a new scene loads. The Scripting API notes that it “only works for root GameObjects or components on root GameObjects”, so the manager must not be a child of another object (Unity Technologies, Scripting API: Object.DontDestroyOnLoad, Unity 6.3). LeavepersistAcrossScenesoff for a manager that should belong to one scene.OnDestroyclearsInstanceso that nothing keeps talking to a destroyed manager.
Any script can now use it without wiring:
public class CoinSound : MonoBehaviour
{
[SerializeField] private AudioClip pickupClip;
private void OnTriggerEnter2D(Collider2D other)
{
if (!other.CompareTag("Player")) return;
AudioManager.Instance.PlaySfx(pickupClip);
}
}Unity’s sample project for its patterns guide contains three versions of this idea: SimpleSingleton (the guard only), Singleton<T> (a generic base class with lazy creation) and PersistentSingleton<T> (the same plus DontDestroyOnLoad), with an AudioManager and a GameManager as example users (Unity Technologies, game-programming-patterns-demo repository on GitHub, 3_Singleton folder, read 2026-10-25).
Generic Singleton<T>
If you have several managers, repeating the guard in each becomes tedious. A generic base class, public class Singleton<T> : MonoBehaviour where T : Component, holds the guard once, and each manager inherits from it: public class GameManager : Singleton<GameManager>. The full, corrected implementation (with the else if (_instance != this) guard and Unity 6’s FindAnyObjectByType) is on unity-gamemanager-pattern, under Generic Singleton
That version adds lazy instantiation: if Instance is read before any manager exists, it searches the scene and, failing that, creates a new GameObject with the component. This is convenient, but the created object has none of the Inspector settings a placed manager would have, so prefer placing the manager in your first scene and treat lazy creation as a fallback.
Resetting static state when domain reload is off
By default Unity reloads the scripting domain on entering Play mode, which resets every static field. If you turn this off for faster iteration (Project Settings > Editor > Enter Play Mode Settings), static fields such as Instance keep their values between Play sessions, and the Manual says you must then reset that state in code, for example with [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] (Unity Technologies, Enter Play mode with domain reload disabled, Unity 6.3 Manual):
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
private static void ResetStatics() => Instance = null;Trade-offs
What Unity’s guide says in favour
For small games that do not need long-term extensibility, Unity’s guide lists three benefits: singletons are quick to learn, user-friendly (any component can reach the instance), and performant, because global access avoids repeated GetComponent or Find calls. It concludes: “If you decide to use singletons in your project, keep them to a minimum… Reserve the singletons for a handful of scripts that can benefit from global access” (Unity Technologies, Level Up Your Code with Game Programming Patterns).
Cautions
- Hidden dependencies. A script that calls
AudioManager.Instancedepends on the audio manager, but nothing in the Inspector or the class’s fields shows it. Unity’s guide warns that global access can “hide many dependencies, making bugs much harder to troubleshoot”. Nystrom’s central objection is the same: a singleton is a global variable, “just encapsulated in a class”, and globals make code harder to reason about. - Tight coupling. Because every script can reach the singleton, many end up depending on it, and changing it affects all of them. Unity’s guide notes that most patterns try to decouple dependencies while singletons “do the opposite”; Nystrom puts it as “by controlling access to instances, you control coupling”.
- Testing. Unit tests should be independent of one another, but a singleton carries state from one test to the next and can change many objects at once, so Unity’s guide lists testing difficulty as a key drawback.
- Scene reloads. Reloading or returning to a scene that contains the manager creates a duplicate, which the guard must destroy. A persistent manager also outlives the scene it was configured in, so any Inspector references it held to objects in that scene stop working once the scene unloads (Unity’s
==comparison treats destroyed objects asnull). Keep persistent managers self-contained, or have scene objects register with them when they start. - Execution order. The order in which different objects’
Awakemethods run is not guaranteed, butStartonly runs after everyAwakein the scene (Unity Technologies, Scripting API: MonoBehaviour.Awake and MonoBehaviour.Start). ReadingInstancefrom another object’sAwakeorOnEnablecan therefore find it stillnull. Read it inStartor later, as unity-gamemanager-pattern explains, or set an explicit order under Project Settings > Script Execution Order. - Lazy creation at a bad moment. Nystrom notes that lazily initialising an expensive system in the middle of gameplay can cause a visible stutter; a manager placed in the first scene avoids this.
- “Manager” creep. Nystrom suggests that many singleton managers exist only because responsibilities were pulled out of the objects they manage: “OOP is about letting objects take care of themselves.” If a manager just pokes at other objects’ data, consider moving that behaviour back into the objects.
Alternatives
| Need | Alternative | Notes |
|---|---|---|
| A few scripts in one scene need the manager | Inspector reference ([SerializeField] private AudioManager audioManager;) | The dependency is visible and can be swapped; see unity-inspector-references and getcomponent-vs-inspector-references. This is the simplest form of dependency injection. |
| Code needs a service but should not care where it comes from | Pass it in (constructor or method parameter, or an Init(audioManager) call from a spawner) | Nystrom’s first suggested alternative; makes dependencies explicit and testable. |
| Many listeners need to know something happened | Events: C# events (observer-pattern) or scriptableobject-event-channels | Listeners depend only on the event or channel asset, not on the manager; a channel asset also exists before any OnEnable runs. |
| Shared data across scenes (settings, score) | ScriptableObject assets (unity-scriptableobjects) | Data lives in an asset that any scene can reference in the Inspector. |
| A large project with many services | Dependency injection frameworks or a service locator | A DI container builds objects and hands each one its dependencies; a service locator (Nystrom has a chapter on it) is a single registry that provides services by type. Both are beyond a beginner project, but worth knowing as the professional direction. |
A reasonable progression is: Inspector reference first; then events for broadcasting; then a singleton only for the one or two systems that truly must be global and persistent.
Other engines
Godot provides autoloads: scripts or scenes listed in Project Settings that the engine loads before the main scene and keeps for the whole run, reachable by name from any script. Unreal Engine offers subsystems (for example a Game Instance Subsystem) whose lifetime the engine manages. Both give global access without hand-written duplicate guards, but they carry the same coupling cautions.
Examples
- Unity’s patterns sample project uses a generic singleton for an
AudioManager(play a sound effect from any GameObject) and aGameManager(Unity Technologies,game-programming-patterns-demo,3_Singleton/Scripts/ExampleUsage). - unity-gamemanager-pattern - a persistent GameManager that owns score and lives and raises events for UI
- object-pool-pattern - Unity’s guide notes that a pool can be designed as a singleton so pooled objects are easy to request
Practice
Build and then stress-test an AudioManager singleton:
- Create two scenes,
Level01andLevel02, and add both to the build profile’s scene list. - Put an
AudioManagerGameObject (root level, with anAudioSource) inLevel01only, using the minimal implementation above. - Add a coin in each scene whose script calls
AudioManager.Instance.PlaySfx(...), and a key press that loads the other scene withSceneManager.LoadScene(inUnityEngine.SceneManagement). - Play
Level01, collect the coin, switch toLevel02, collect the coin there, then switch back toLevel01.
Success test:
- coin sounds play in both scenes, and the Hierarchy shows the manager under DontDestroyOnLoad
- returning to
Level01logs the “Duplicate AudioManager” warning once and leaves exactly one manager - commenting out the duplicate guard and repeating step 4 produces two managers; you can explain why
- starting Play mode directly in
Level02gives aNullReferenceException; you can explain why and name two fixes
Extension:
- refactor one coin to take the
AudioManagerthrough a[SerializeField]field instead ofInstance, and note what that makes visible in the Inspector that the singleton version hid - replace the coin-to-audio call with a ScriptableObject event channel that the
AudioManagerlistens to, so the coin no longer references the manager at all
Self-test
- What two ideas does the singleton pattern combine, and which one is usually the one people actually want?
- Why does a Unity singleton need a duplicate guard in
Awake? - What does
DontDestroyOnLoaddo, and what restriction does it have? - Give two drawbacks of singletons named in Unity’s own patterns guide.
- Why can reading
Instancein another object’sAwakefail, and where is it safer to read it? - Name two alternatives to a singleton and when each fits.
Answers
- Restricting a class to a single instance, and global access to that instance. Most code only wants the global access.
- Because a scene can contain more than one copy (for example after reloading the scene that holds the manager); without the guard you get two managers and doubled behaviour.
- It keeps the object alive when a new scene loads. It only works on root GameObjects (or components on them).
- Any two of: it hides dependencies, making bugs harder to troubleshoot; it makes testing difficult; it encourages tight coupling.
- The order of
Awakecalls between objects is not guaranteed, so the manager’sAwakemay not have setInstanceyet.Startis safer, because it runs only after everyAwakein the scene. - Any two of: an Inspector reference, when a few scripts in one scene need the manager; passing the dependency in, when you want it explicit and testable; events or ScriptableObject event channels, when many listeners need to react to a change; ScriptableObject assets, for shared data across scenes; dependency injection or a service locator, in larger projects.
Related
- unity-gamemanager-pattern - the singleton applied to a GameManager, including the full generic
Singleton<T> - unity-object-communication - the wider choice of how scripts talk to each other
- observer-pattern - events as the decoupled alternative for broadcasting changes
- scriptableobject-event-channels - listeners that need no reference to any manager
- unity-scriptableobjects - shared data assets as an alternative to global state
- unity-inspector-references - the explicit, wired alternative
- monobehaviour-lifecycle - why
AwakeandStartorder matters forInstance - object-pool-pattern - often combined with a singleton for easy access
- source-unity-game-programming-patterns - Unity’s patterns e-book, including its singleton chapter
External references
- Robert Nystrom, Game Programming Patterns, “Singleton”: https://gameprogrammingpatterns.com/singleton.html
- Unity Technologies,
game-programming-patterns-demo(sample project for the e-book): https://github.com/Unity-Technologies/game-programming-patterns-demo - Unity Technologies, Scripting API: Object.DontDestroyOnLoad, Unity 6.3: https://docs.unity3d.com/6000.3/Documentation/ScriptReference/Object.DontDestroyOnLoad.html
- Unity Technologies, Enter Play mode with domain reload disabled, Unity 6.3 Manual: https://docs.unity3d.com/6000.3/Documentation/Manual/domain-reloading.html