Last updated: Apr 29, 2026
Singleton
The Singleton pattern restricts a class to a single instance and provides a global access point to that instance.
Intent
Sometimes you need exactly one object to coordinate actions across the system — a configuration manager, a connection pool, a logger. The Singleton pattern guarantees that a class has only one instance and provides a well-known access point.
Examples in TypeScript
Class-Based Singleton with Object.freeze
let instance: DatabaseConnection | null = null;
class DatabaseConnection {
private host: string;
private port: number;
constructor(host: string, port: number) {
if (instance) {
throw new Error("DatabaseConnection already initialized");
}
instance = this;
this.host = host;
this.port = port;
}
getConnectionString(): string {
return `${this.host}:${this.port}`;
}
}
const dbInstance = Object.freeze(new DatabaseConnection("localhost", 5432));
export { dbInstance };
Object Literal Singleton
const appConfig = Object.freeze({
apiUrl: "https://api.example.com",
timeout: 5000,
retries: 3,
summary(): string {
return `${this.apiUrl} (timeout: ${this.timeout}ms)`;
},
});
export { appConfig };
ES2015 Modules Are Singletons by Default
In ES2015+, a module is evaluated once regardless of how many files import it. The exported bindings are shared across all consumers, which means any top-level object you export already behaves as a singleton.
When to Use It
- You need exactly one instance of a class accessible from a well-known access point.
- The single instance should be extensible by subclassing, and clients should be able to use the extended instance without modifying their code.
Common Real-World Uses
- Database connection pools
- Application configuration objects
- Logging services
Trade-Offs
| Advantage | Disadvantage |
|---|---|
| Controlled access to sole instance | Hard to unit-test (global state) |
| Reduced namespace pollution | Can hide dependencies |
| Lazy initialization | Potential thread-safety issues |
Related Patterns
- Factory Method — can use Singleton to ensure only one factory exists.
- Abstract Factory — often implemented as a Singleton.
- Builder — can be combined with Singleton to reuse a complex build process.