The Singleton pattern is one of the most commonly used design patterns in Unity projects. It provides a way to ensure that a class has only one shared instance and gives other systems a convenient way to access it.
For small projects, a Singleton can be extremely useful. However, using Singleton everywhere can make a project difficult to maintain.
In this guide, we’ll look at what the Singleton pattern is, how to implement it in C#, how it works in Unity, and when you should—or shouldn’t—use it.
What Is the Singleton Pattern?
A Singleton ensures that a class has only one instance during its lifetime.
Conceptually:
Game
│
├── GameManager
│ ↓
│ ONE INSTANCE
│
├── Player
│
└── Enemy
Instead of creating multiple GameManager objects, other systems access the same instance.
For example:
GameManager.Instance.StartGame();
The important parts are:
- The constructor or creation process is controlled.
- Only one instance is allowed.
- The instance is globally accessible.
A Basic C# Singleton
A simple implementation looks like this:
public class GameManager
{
private static GameManager instance;
public static GameManager Instance
{
get
{
if (instance == null)
{
instance = new GameManager();
}
return instance;
}
}
private GameManager()
{
}
}
Now you can access the class through:
GameManager.Instance
For example:
GameManager.Instance.StartGame();
The constructor is private, preventing other classes from directly creating another GameManager.
Why Use a Singleton?
Singletons are useful when a system genuinely represents a single global service.
Common examples include:
- Game Manager
- Audio Manager
- Save Manager
- Settings Manager
- Input Manager
- Achievement Manager
- Analytics Manager
- Configuration Manager
For example, your game may only need one audio system.
AudioManager
│
┌────┼────┐
↓ ↓ ↓
Menu Player Enemy
All systems can communicate with the same Audio Manager.
Singleton in Unity
Unity introduces an additional consideration because MonoBehaviour objects are managed by the Unity engine.
A common Unity Singleton looks like this:
using UnityEngine;
public class GameManager : MonoBehaviour
{
public static GameManager Instance { get; private set; }
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
DontDestroyOnLoad(gameObject);
}
}
Now other scripts can access:
GameManager.Instance
Understanding Awake()
The Awake() method runs when Unity initializes the object.
This is where we check whether another instance already exists.
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
If another instance exists, the new object is destroyed.
Otherwise:
Instance = this;
registers the current object as the Singleton.
Using DontDestroyOnLoad()
Normally, Unity destroys scene objects when you load another scene.
For example:
Main Menu
↓
Gameplay
Objects in the Main Menu scene are normally destroyed.
If your GameManager needs to survive scene changes:
DontDestroyOnLoad(gameObject);
tells Unity to keep it alive.
The structure becomes:
Scene 1
│
└── GameManager
│
↓
Scene Change
│
↓
Scene 2
│
└── Same GameManager
This is useful for persistent systems such as audio, save data, and game state.
The Duplicate Instance Problem
A common problem occurs when you put a Singleton prefab into multiple scenes.
For example:
Scene 1
└── GameManager
Scene 2
└── GameManager
When Scene 2 loads, Unity may create another GameManager.
The Singleton protects against this:
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
The first instance survives.
The duplicate is destroyed.
A Better Generic Singleton
If your project contains several Singleton systems, you don’t necessarily want to repeat the same code.
You can create a generic base class:
using UnityEngine;
public abstract class Singleton<T> : MonoBehaviour
where T : MonoBehaviour
{
public static T Instance { get; private set; }
protected virtual void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this as T;
DontDestroyOnLoad(gameObject);
}
}
Then:
public class AudioManager : Singleton<AudioManager>
{
}
And:
public class SaveManager : Singleton<SaveManager>
{
}
You can access them with:
AudioManager.Instance
SaveManager.Instance
This reduces duplicated Singleton code.
Example: Audio Manager
A simple Audio Manager might look like:
using UnityEngine;
public class AudioManager : MonoBehaviour
{
public static AudioManager Instance { get; private set; }
[SerializeField]
private AudioSource musicSource;
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
DontDestroyOnLoad(gameObject);
}
public void PlayMusic(AudioClip clip)
{
musicSource.clip = clip;
musicSource.Play();
}
}
Another script can then call:
AudioManager.Instance.PlayMusic(battleMusic);
This is convenient because the caller doesn’t need to know where the AudioManager exists.
The Biggest Problem With Singletons
Singletons are convenient—but convenience can become a problem.
Consider:
GameManager.Instance
AudioManager.Instance
SaveManager.Instance
UIManager.Instance
PlayerManager.Instance
InventoryManager.Instance
EnemyManager.Instance
QuestManager.Instance
NetworkManager.Instance
Eventually, almost every system becomes globally accessible.
This creates global state.
Your classes become tightly coupled.
For example:
public class Enemy
{
public void Die()
{
GameManager.Instance
.UIManager
.ScoreManager
.AudioManager
.SaveManager
.UpdateSomething();
}
}
Now Enemy depends on many global systems.
That makes the code harder to:
- Test
- Refactor
- Reuse
- Debug
- Understand
Singleton vs Dependency Injection
A cleaner architecture for larger projects can use Dependency Injection (DI).
Instead of:
AudioManager.Instance.PlaySound(sound);
you could provide the dependency:
public class Player
{
private readonly IAudioService audioService;
public Player(IAudioService audioService)
{
this.audioService = audioService;
}
}
Now the Player doesn’t need to know how the audio system is created.
This reduces coupling.
The general idea is:
Singleton
Player → Global AudioManager
versus:
Dependency Injection
AudioService → Player
The second approach becomes increasingly valuable as the project grows.
When Should You Use a Singleton?
Singletons are a reasonable choice when:
✔ There should genuinely be one instance
For example, one application-level audio service.
✔ The system has global scope
For example, global game configuration.
✔ The system has a long lifetime
For example, a persistent save service.
✔ The convenience outweighs the coupling
For small and medium-sized projects, this can be a practical trade-off.
When Should You Avoid a Singleton?
Avoid creating a Singleton simply because accessing an object is convenient.
Don’t turn every manager into:
SomethingManager.Instance
You should especially be cautious when:
- Objects have different lifetimes
- Multiple instances may be useful later
- You need strong testability
- Systems are tightly coupled
- Dependencies are unclear
- You’re building a large architecture
A Singleton isn’t automatically good architecture.
Singleton vs Static Class
These two concepts are often confused.
A static class:
public static class GameUtility
{
public static int ClampHealth(int value)
{
return Mathf.Clamp(value, 0, 100);
}
}
doesn’t have an instance.
You use:
GameUtility.ClampHealth(150);
A Singleton has an actual object instance:
GameManager.Instance
This means it can:
- Hold state
- Implement interfaces
- Be referenced as an object
- Work with Unity’s
MonoBehaviourlifecycle
Use static classes for stateless utilities.
Use Singleton-like services when you genuinely need a shared instance.
Common Singleton Mistakes
Mistake 1 — Creating Multiple Instances
Always protect against duplicates.
Mistake 2 — Everything Is a Singleton
This creates global-state chaos.
Mistake 3 — Hidden Dependencies
A class may secretly depend on five different Singleton systems.
Mistake 4 — Incorrect Scene Management
Using DontDestroyOnLoad() everywhere can leave unwanted objects alive.
Mistake 5 — Testing Problems
Global state can make unit tests harder because one test can affect another.
A Practical Unity Architecture
For a small Unity project, you might have:
GameBootstrap
│
├── GameManager
├── AudioManager
├── SaveManager
└── SettingsManager
Then gameplay systems communicate with those services where appropriate.
For a larger project, consider moving toward:
Bootstrap
│
├── Service Container
│ ├── Audio Service
│ ├── Save Service
│ └── Analytics Service
│
└── Gameplay Systems
├── Player
├── Enemy
├── Inventory
└── Quest
This gives you clearer separation of responsibilities.
Final Thoughts
The Singleton pattern isn’t inherently bad.
The real problem is using it for everything.
For a small Unity game, a Singleton can be a simple and effective solution for systems such as:
- Audio
- Save data
- Game state
- Settings
- Configuration
As your project grows, however, consider alternatives such as Dependency Injection, interfaces, service containers, events, and composition.
The most important lesson is:
Use Singleton because the system genuinely needs one shared instance—not simply because
Class.Instanceis convenient.
Understanding when to use a pattern is more valuable than simply knowing how to implement it.