Suggest an editImprove this articleRefine the answer for “Singleton pattern”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**Singleton pattern** is a creational design pattern that ensures a class has exactly one instance with a global access point. ```typescript class Database { private static instance: Database; private constructor() {} static getInstance(): Database { if (!Database.instance) { Database.instance = new Database(); } return Database.instance; } } const db1 = Database.getInstance(); const db2 = Database.getInstance(); console.log(db1 === db2); // true - same object ``` **Key:** private constructor blocks `new`; `getInstance()` returns the same object every time. Use for loggers, configs, or connection pools.Shown above the full answer for quick recall.Answer (EN)Image**Singleton pattern** is a creational design pattern that restricts a class to a single instance and provides a global access point to it. ## Theory ### TL;DR - Think of it like the White House: one building, one president, everyone goes through the same address. - Main difference: a regular class lets you call `new` as many times as you want; Singleton blocks every `new` after the first one. - Use when exactly one object should control a shared resource (logger, DB pool, config). Skip it for stateless utilities. - In Node.js clusters, each process gets its own Singleton instance. It is NOT shared across processes. ### Quick example ```typescript class Singleton { private static instance: Singleton; private constructor() { // private: blocks new Singleton() from outside } static getInstance(): Singleton { if (!Singleton.instance) { Singleton.instance = new Singleton(); // created once } return Singleton.instance; } } const a = Singleton.getInstance(); const b = Singleton.getInstance(); console.log(a === b); // true - same object ``` Two calls, one object. That is the whole mechanism. ### Key difference A plain class lets anyone call `new` and get a fresh object each time. Singleton makes the constructor private and routes all access through a static `getInstance()` method. The first call creates the object and stores it in a static field. Every call after that returns the same stored reference. No new allocations, no duplicates. ### When to use - **Logger** - one log stream for the whole app, not one per module. - **DB connection pool** - share limited connections across the codebase. - **App config** - load settings once at startup, read anywhere. - **Cache** - one in-memory store, consistent state across features. - **Skip it** when the class holds no shared state. A utility with pure functions does not need Singleton. If you need to mock it in tests, consider dependency injection instead. ### How the engine handles this V8 (Node.js/Chrome) stores the private static field `#instance` as a hidden class property, inaccessible from outside. Each call to `getInstance()` does a fast static field lookup. If the field is `null`, it allocates once via `new` and caches the reference. Subsequent calls skip allocation entirely. One thing that catches developers off guard: in Node.js with worker threads or in cluster mode, each process or worker has its own memory space. So each gets its own Singleton instance. This trips up most developers the first time they deploy to a load-balanced environment. If you actually need shared state across processes, use an external store like Redis, not a Singleton. ### Common mistakes **Clusters break the "one instance" guarantee** ```javascript // Each worker process prints a different PID const singleton = require('./singleton'); console.log(singleton.getInstance().id); // worker 1: 1234, worker 2: 1235 ``` If your app runs multiple Node.js processes, Singleton does not give you a single shared instance. Use IPC or Redis for that. **Public constructor lets anyone bypass the gatekeeper** ```javascript // Wrong class Config { constructor() { this.settings = {}; } // nothing stops new Config() static getInstance() { /* ... */ } } const c1 = new Config(); // bypasses getInstance entirely const c2 = Config.getInstance(); // different object ``` Make the constructor private (TypeScript) or throw inside it (plain JS). **Testing becomes painful with shared state** ```javascript // Test pollution - Logger keeps state between tests test('logs error', () => { Logger.getInstance().log('error'); }); test('empty log on start', () => { // Logger still has the entry from the previous test expect(Logger.getInstance().getLogs()).toHaveLength(0); // fails }); ``` Add a `resetInstance()` method for test environments or use dependency injection instead of a bare Singleton. **Serialization crashes on circular reference** ```javascript JSON.stringify(Singleton.getInstance()); // Error: circular structure ``` The static `instance` field points back to the object itself. Add a `toJSON()` method that returns only the data you need. ### Real-world usage - **Winston** (Node logger): `createLogger()` returns one logger per transport config. - **Express**: the `app` object is one instance per server process. - **Redux DevTools**: one store instance hooks into the React app. - **React Context**: a Provider creates one value shared down the component tree, which behaves as a Singleton for that subtree. - **Lodash**: the utility object is a module-level Singleton, though you should import individual functions for tree-shaking. When you genuinely need testable, mockable instances, look at InversifyJS or plain dependency injection. Singleton is for true uniques. ### Follow-up questions **Q:** How do you make a Singleton thread-safe in JavaScript? **A:** In single-threaded JS, a simple `if (!instance)` check is fine. With worker threads, concurrent `getInstance()` calls during async initialization can race. Use `??=` for atomic-ish assignment or guard the init with a flag. **Q:** What is the difference between Singleton and a global variable? **A:** A global variable is just a value, anyone can overwrite it. Singleton controls creation (lazy init, exactly once) and can carry methods, validation, and state. Both share the problem of hidden dependencies. **Q:** How does Singleton violate SOLID? **A:** It breaks Single Responsibility (the class manages its own lifecycle AND does its actual job) and Dependency Inversion (callers hardcode `getInstance()` instead of receiving an interface). **Q:** How do you mock a Singleton in Jest? **A:** Use `jest.spyOn(MyClass, 'getInstance').mockReturnValue(mockInstance)`. Or add a static `resetInstance()` that clears the private field and call it in `beforeEach`. **Q:** (Senior) Why avoid Singleton for a DB pool in microservices? **A:** Each pod scales independently and needs its own pool sized to its load. A Singleton inside one process is fine, but the assumption of "one pool for the whole app" breaks when the app is split across 20 pods. Use a connection string in config and a pool library like `pg-pool` per service. ## Examples ### Basic: TypeScript Singleton for app config ```typescript class AppConfig { private static instance: AppConfig; private settings: Record<string, string> = {}; private constructor() { // Config is loaded exactly once this.settings = { env: process.env.NODE_ENV ?? 'development' }; } static getInstance(): AppConfig { if (!AppConfig.instance) { AppConfig.instance = new AppConfig(); } return AppConfig.instance; } get(key: string): string { return this.settings[key] ?? ''; } } const config1 = AppConfig.getInstance(); const config2 = AppConfig.getInstance(); console.log(config1 === config2); // true console.log(config1.get('env')); // 'development' ``` Both variables hold the same object. `settings` is loaded exactly once, no matter how many modules call `getInstance()`. ### Intermediate: Shared logger in Express ```javascript class Logger { static #instance; #logs = []; constructor() { if (Logger.#instance) throw new Error('Use Logger.getInstance()'); Logger.#instance = this; } static getInstance() { return Logger.#instance ?? (Logger.#instance = new Logger()); } log(message) { const entry = `${new Date().toISOString()}: ${message}`; this.#logs.push(entry); console.log(entry); } getLogs() { return this.#logs; } } // Both routes share the same Logger and the same #logs array app.get('/users', (req, res) => { Logger.getInstance().log('GET /users'); res.json([]); }); app.post('/orders', (req, res) => { Logger.getInstance().log('POST /orders'); res.json({ id: 1 }); }); ``` Both routes call `getInstance()` and get back the same object, so `#logs` accumulates entries from every request in one place. ### Senior: Why tests break without instance reset ```javascript class Counter { static #instance; #count = 0; static getInstance() { return Counter.#instance ?? (Counter.#instance = new Counter()); } static resetInstance() { Counter.#instance = null; // expose only for tests } increment() { this.#count++; } value() { return this.#count; } } // Test file beforeEach(() => Counter.resetInstance()); test('starts at zero', () => { expect(Counter.getInstance().value()).toBe(0); // passes every time }); test('increments correctly', () => { Counter.getInstance().increment(); expect(Counter.getInstance().value()).toBe(1); // passes every time }); ``` Without `resetInstance()`, the second test would see a count of 1 left over from the first. The shared instance is exactly why Singletons pollute test state when you do not plan for it.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.