The Singleton Pattern guarantees a class or module has exactly one shared instance, accessible from anywhere. In JavaScript, this is often achieved trivially through the module system itself, without needing the more elaborate implementations seen in other languages.
1The Singleton Pattern | JavaScript Tutorial - In-Depth Guide Part 1
A Singleton guarantees that only one instance of a particular object ever exists throughout the application, and provides a single, globally-accessible reference to it.
const AppConfig = (function () {
let instance;
function createInstance() { return { theme: 'light', locale: 'en' }; }
return {
getInstance() {
if (!instance) instance = createInstance();
return instance;
},
};
})();Exactly One Instance
2The Singleton Pattern | JavaScript Tutorial - In-Depth Guide Part 2
In JavaScript, ES modules make the Singleton Pattern almost automatic: a module's top-level state is evaluated exactly once and cached, so every import of that module receives the exact same shared object.
// config.js โ this object is created once, shared by every importer:
export const config = { theme: 'light', locale: 'en' };
// any other file:
import { config } from './config.js'; // same shared object everywhereES Modules Make It Automatic
3The Singleton Pattern | JavaScript Tutorial - In-Depth Guide Part 3
Legitimate singleton use cases include shared application configuration, a single logging instance, or a connection pool where having multiple independent instances would be wasteful or incorrect.
// A single, shared logger instance used app-wide:
export const logger = createLogger({ level: 'info' });Legitimate Use Cases
4The Singleton Pattern | JavaScript Tutorial - In-Depth Guide Part 4
Overusing singletons for things that AREN'T genuinely singular creates hidden global state, coupling unrelated parts of the codebase together implicitly through the shared instance.
// Anti-pattern: using a singleton just for convenience,
// not because there should genuinely be only one:
export const currentUser = { name: null }; // mutated from many unrelated placesThe Overuse Risk
5The Singleton Pattern | JavaScript Tutorial - In-Depth Guide Part 5
Singletons make unit testing harder, since shared, persistent state can leak between tests unless it's explicitly reset โ a well-known trade-off worth designing around deliberately.
// Testing-friendly singleton: exposes a reset hook
export const cache = {
data: new Map(),
resetForTesting() { this.data.clear(); },
};The Testing Trade-off
6Step-by-Step Breakdown
A Singleton guarantees that only one instance of a particular object ever exists throughout the application, and provides a single, globally-accessible reference to it.
In JavaScript, ES modules make the Singleton Pattern almost automatic: a module's top-level state is evaluated exactly once and cached, so every import of that module receives the exact same shared object.
Checkpoint: If two different files import the same exported object from an ES module, do they get the same shared instance?
- โYes, module state is evaluated once and shared
- โNo, each import creates a fresh copy
Legitimate singleton use cases include shared application configuration, a single logging instance, or a connection pool where having multiple independent instances would be wasteful or incorrect.
Overusing singletons for things that AREN'T genuinely singular creates hidden global state, coupling unrelated parts of the codebase together implicitly through the shared instance.
Singletons make unit testing harder, since shared, persistent state can leak between tests unless it's explicitly reset โ a well-known trade-off worth designing around deliberately.
Checkpoint: Can shared singleton state accidentally leak between separate unit tests if not explicitly reset?
- โYes, this is a well-known testing trade-off of singletons
- โNo, singletons are automatically isolated per test
Next, we'll explore 'The Observer Pattern'.
Level Up ๐
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1A Singleton Focus-Trap Manager Can Coordinate Nested Accessible Dialogs
A singleton managing the currently active focus trap ensures that if multiple dialogs are opened in sequence, only one focus trap is ever active at a time, correctly restoring focus to the previous dialog (or trigger element) when an inner one closes.
SEO Implications
- 1
No Direct SEO Effect
The Singleton Pattern is an application-architecture concern; SEO relevance is limited to general application reliability and maintainability.
Best Practices
Reach for a Singleton Only When the Resource Is Genuinely Singular
Configuration, a single connection pool, or a single logger are legitimate; using a singleton purely for easy access from anywhere often introduces unnecessary hidden coupling instead.
Design Singletons with Testability in Mind from the Start
Expose an explicit reset mechanism, or prefer passing dependencies explicitly (dependency injection) in code paths where isolated, repeatable unit tests matter most.
Frequent Bugs
A singleton holding mutable state causes one test to leave residual state that silently affects the outcome of a later, unrelated test.
Add an explicit reset method called in a test setup/teardown hook, or avoid a true singleton in favor of creating a fresh instance per test via dependency injection.
Reaching for a singleton purely for global convenience (like a "current user" object mutated from many unrelated files), making it hard to trace which code is responsible for a given state change.
Consider whether the resource is truly singular; if not, pass the relevant data explicitly through function parameters or a more structured state-management approach instead.
Real-World Examples
A Shared Database Connection Pool
A backend service needed exactly one connection pool shared across all incoming requests, rather than each request opening its own redundant set of connections.
// db.js
let pool;
export function getPool() {
if (!pool) pool = createConnectionPool({ max: 10 });
return pool;
}