Singleton Pattern
The Singleton pattern makes sure a class has exactly one instance and gives everyone the same one — useful for app settings, caches and connection pools.
On this page · 5 min · Intermediate
On this page
- In simple words
- Learning objectives
- Explanation
- Syntax
- Code example
- Step by step
- Real-world use
- Common mistakes
- Best practices
- Remember this
- Practice exercise
- Mini quiz
- Related topics
- My notes
- Reading time
- 5 min
- Difficulty
- Intermediate
- Updated
- Oct 28, 2026
Related tutorials
In simple words#
A country has one Prime Minister at a time. Singleton ensures a class has exactly one shared instance.
- Singleton
- Only one instance exists.
- Global access
- Everyone uses the same instance.
- In ASP.NET Core
- Prefer AddSingleton in DI over hand-written singletons.
Learning objectives#
- Implement a Singleton in JavaScript and C#
- Understand why the constructor must be protected
- Use module and DI singletons instead of hand-made ones
- Know the testing and threading pitfalls
Explanation#
A Singleton hides its constructor and exposes a static access point (AppConfig.instance). The first call creates the object; later calls return the same one.
In C#, the simplest thread-safe version uses Lazy<T>, which creates the instance once even if many threads ask at the same moment.
In JavaScript, a module is already a singleton: every import of a module gets the same exported object. That is the most common JavaScript “singleton”.
In ASP.NET Core, prefer builder.Services.AddSingleton<ICache, MemoryCache>(): the container guarantees one instance, and tests can still replace it.
Singletons are global state in disguise. They make tests depend on each other and hide dependencies. Use them for truly shared, mostly read-only things.
Syntax#
public sealed class AppConfig
{
private static readonly Lazy<AppConfig> _instance = new(() => new AppConfig());
public static AppConfig Instance => _instance.Value;
private AppConfig() { } // nobody else can call new
public string Theme { get; set; } = "light";
}
// Preferred in ASP.NET Core:
builder.Services.AddSingleton<IAppConfig, AppConfig>();
Code example: One configuration for the whole app#
class AppConfig {
static #instance = null;
#settings = new Map();
constructor() {
if (AppConfig.#instance) throw new Error('Use AppConfig.instance');
}
static get instance() {
if (!AppConfig.#instance) AppConfig.#instance = new AppConfig();
return AppConfig.#instance;
}
set(key, value) { this.#settings.set(key, value); }
get(key) { return this.#settings.get(key); }
}
const a = AppConfig.instance;
a.set('theme', 'dark');
const b = AppConfig.instance; // somewhere else in the app
console.log(a === b);
console.log(b.get('theme'));
try { new AppConfig(); } catch (e) { console.log(e.message); }
// The everyday JavaScript singleton: a module-level object
const idGenerator = (() => {
let last = 0;
return { next: () => ++last };
})();
console.log(idGenerator.next(), idGenerator.next());
true dark Use AppConfig.instance 1 2
Step-by-step explanation#
- static #instance holds the single object; it starts as null.
- The instance getter creates the object on first use (lazy creation) and returns the same one afterwards.
- a and b are the same object, so a setting saved through a is visible through b.
- Calling new directly is blocked once the instance exists.
- idGenerator shows the simpler module-style singleton: one closure, shared state.
Real-world use case#
An ASP.NET Core app registers IMemoryCache, HttpClient handlers and configuration as singletons. One cache serves every request, so data loaded once is reused across users.
Common mistakes#
A singleton holding the “current user” leaks data between requests and users. Request data belongs in scoped services.
if (_instance == null) _instance = new() can create two instances under load. Use Lazy<T> or the DI container.
Calling AppConfig.Instance deep inside a method makes the class impossible to test with different settings. Inject the config instead.
Best practices#
- Prefer DI singletons over hand-written ones
- Keep singleton state read-only or thread-safe
- Use Lazy<T> for hand-written C# singletons
- Never store per-user data in a singleton
Remember this#
Singleton = one instance, one access point.
In JS, a module is already a singleton.
In ASP.NET Core: AddSingleton, not static Instance.
Practice exercise#
Your task: Create a Logger singleton with a static getInstance() method and a log(msg) method that stores messages in an array. Log from two “different places” and show both messages are in the same logger.
Need a hint?
Show solution
class Logger {
static #instance;
messages = [];
static getInstance() { return (Logger.#instance ??= new Logger()); }
log(msg) { this.messages.push(msg); }
}
Logger.getInstance().log('from checkout');
Logger.getInstance().log('from login');
console.log(Logger.getInstance().messages); // [ 'from checkout', 'from login' ]
console.log(Logger.getInstance() === Logger.getInstance()); // true
Mini quiz#
What does the Singleton pattern guarantee?
Want more? Practise all OOP Concepts MCQs · OOP Concepts interview questions
My notes#
Saved in this browser.