🏗️ Creational

Singleton Pattern

Ensures a class has only one instance and provides a global point of access to it. The Singleton pattern restricts instantiation of a class to a single object, which is useful when exactly one object is needed to coordinate actions across the system.

Problem

Some classes should have exactly one instance. A global variable can provide access, but it doesn't prevent you from creating multiple instances. Additionally, solutions like global variables pollute the namespace and can be overwritten at any point.

Solution

Make the default constructor private and create a static creation method that acts as a constructor. This method calls the private constructor to create an object and saves it in a static field. All following calls to this method return the cached object. The Singleton pattern lets you access the same object from anywhere in the program while protecting that instance from being overwritten by other code.

Participants

RoleResponsibility
SingletonDefines a static getInstance() method that returns the same instance of its own class. The constructor is hidden from client code.

TypeScript Example

TypeScript
class Database {
  private static instance: Database;
  private connection: string;

  private constructor(uri: string) {
    this.connection = uri;
    console.log("Connected to", uri);
  }

  static getInstance(uri = "mongodb://localhost"): Database {
    if (!Database.instance) {
      Database.instance = new Database(uri);
    }
    return Database.instance;
  }

  query(sql: string): string {
    return `Executing "${sql}" on ${this.connection}`;
  }
}

const db1 = Database.getInstance();
const db2 = Database.getInstance();
console.log(db1 === db2); // true

Real-World Example

A database connection pool is a classic real-world Singleton. An application typically needs one shared pool that manages a limited number of connections. Creating multiple pools would waste resources and potentially exceed connection limits. Similarly, logging frameworks, configuration managers, and thread pools use the Singleton pattern to ensure a single coordinated instance across the application.

When to Use

  • A class should have a single instance available to all clients
  • You need stricter control over global variables
  • Managing shared resources like database connections or file systems
  • Coordinating system-wide actions from a single place

When Not to Use

  • Unit testing becomes difficult because the Singleton carries state between tests
  • The pattern violates the Single Responsibility Principle by controlling its own creation and lifecycle
  • When multi-threaded environments require special treatment to prevent multiple threads from creating separate instances
  • If the class has many reasons to change, coupling everything through a Singleton amplifies the impact of changes

Understanding the Singleton Pattern

The Singleton pattern is one of the most important creational design patterns in object-oriented software design. Originally cataloged by the Gang of Four (Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides) in their seminal 1994 book "Design Patterns: Elements of Reusable Object-Oriented Software," this pattern continues to be a cornerstone of modern software architecture.

Ensures a class has only one instance and provides a global point of access to it. The Singleton pattern restricts instantiation of a class to a single object, which is useful when exactly one object is needed to coordinate actions across the system. The pattern involves the following key participants: Singleton. Each participant has a well-defined role, and the interactions between them create a flexible, maintainable structure that can evolve with changing requirements.

In TypeScript and modern JavaScript development, the Singleton pattern is particularly valuable because the language's type system and interface support allow you to express the pattern with compile-time safety. TypeScript generics can make Singleton implementations even more flexible and reusable while maintaining strong type checking throughout the pattern's structure.

Knowing when to apply the Singleton pattern is as important as knowing how. Common use cases include: A class should have a single instance available to all clients; You need stricter control over global variables; Managing shared resources like database connections or file systems. However, overusing design patterns can lead to unnecessarily complex code. Always evaluate whether the pattern genuinely solves your problem or if a simpler approach would suffice.

The Singleton pattern is related to several other design patterns: Factory Method, Abstract Factory, Builder, Prototype. Understanding these relationships helps you choose the right pattern for your specific situation and combine patterns effectively when building complex systems.

Related Patterns

More Creational Patterns

Explore All Design Patterns

Browse our complete reference of 23 design patterns with TypeScript examples, UML participants, and practical guidance.