Singleton Pattern
A singleton ensures a class or module has only one instance and provides a global access point to it.
Module-based singleton (most common in JS)
ts
// logger.ts - module is evaluated once, instance is shared
class Logger {
private logs: string[] = [];
log(message: string) {
const entry = `[${new Date().toISOString()}] ${message}`;
this.logs.push(entry);
console.log(entry);
}
getLogs() { return [...this.logs]; }
}
export const logger = new Logger(); // one instance, shared across importsts
// anywhere in the app
import { logger } from './logger';
logger.log('User signed in');Class-based singleton
ts
class Store {
private static instance: Store | null = null;
private state = {};
private constructor() {} // prevent direct instantiation
static getInstance(): Store {
if (!Store.instance) {
Store.instance = new Store();
}
return Store.instance;
}
}
const store = Store.getInstance();Common singletons in frontend
ts
// query client - one instance per app
const queryClient = new QueryClient();
// axios instance - shared config
const http = axios.create({ baseURL: '/api', timeout: 10000 });
// zustand store - one store
const useStore = create((set) => ({ ... }));Trade-offs
| Pro | Con |
|---|---|
| Global access point | Hidden dependencies |
| Shared state/config | Hard to test (shared state bleeds between tests) |
| Resource efficient | Tight coupling |
| Simple to use | Difficult to mock |
In testing, singletons cause the most pain - one test's state can affect another. The fix is to reset state between tests or provide a
reset()method. ES modules make accidental singletons very easy in JavaScript.
updated
did you know it?