image de chargement
Back to glossary

Singleton

Design pattern ensuring a class has only one global instance with a single point of access.

Updated on January 10, 2026

The Singleton is a creational design pattern that ensures a class has only one instance throughout the application lifecycle while providing a global access point to that instance. This pattern is used to control access to shared resources such as database connections, configuration managers, or system services.

Singleton Pattern Fundamentals

  • Private constructor preventing direct class instantiation
  • Private static variable storing the single class instance
  • Public static method (getInstance) always returning the same instance
  • Lazy or eager initialization depending on requirements

Benefits of Singleton

  • Guarantees strict control over access to a single shared resource
  • Saves memory by avoiding creation of multiple instances
  • Provides a simplified global access point to the instance
  • Enables lazy initialization to optimize performance
  • Facilitates coordination between different application components

Practical Example in TypeScript

DatabaseConnection.ts
class DatabaseConnection {
  private static instance: DatabaseConnection;
  private connectionString: string;
  private isConnected: boolean = false;

  // Private constructor to prevent direct instantiation
  private constructor() {
    this.connectionString = process.env.DB_URL || '';
  }

  // Public method to get the unique instance
  public static getInstance(): DatabaseConnection {
    if (!DatabaseConnection.instance) {
      DatabaseConnection.instance = new DatabaseConnection();
    }
    return DatabaseConnection.instance;
  }

  public connect(): void {
    if (!this.isConnected) {
      console.log(`Connecting to: ${this.connectionString}`);
      this.isConnected = true;
    }
  }

  public query(sql: string): void {
    if (this.isConnected) {
      console.log(`Executing: ${sql}`);
    } else {
      throw new Error('Database not connected');
    }
  }
}

// Usage
const db1 = DatabaseConnection.getInstance();
const db2 = DatabaseConnection.getInstance();

console.log(db1 === db2); // true - same instance
db1.connect();
db1.query('SELECT * FROM users');

This example illustrates a database connection implemented as a Singleton, ensuring only one connection is created and shared throughout the application, avoiding expensive multiple connections.

Pattern Implementation

  1. Declare the class constructor as private to block the new operator
  2. Create a private static property to store the unique instance
  3. Implement a static getInstance() method that creates the instance if needed
  4. Handle synchronization in multi-threaded environments if applicable
  5. Consider using ES6 modules for a simpler approach in modern JavaScript

Beware of Anti-Patterns

Singleton is often considered an anti-pattern due to its global nature that complicates unit testing, creates hidden dependencies, and violates the single responsibility principle. Prefer dependency injection and IoC containers to manage shared instances in modern applications.

Alternatives and Use Cases

In modern applications, ES6 modules in JavaScript/TypeScript naturally act as singletons without requiring complex implementation. Dependency injection frameworks like NestJS, Angular, or Spring offer 'singleton' scope mechanisms that are more testable and maintainable.

modern-singleton.ts
// Modern approach with ES6 module
export class ConfigService {
  private config: Record<string, any>;

  constructor() {
    this.config = {
      apiUrl: process.env.API_URL,
      timeout: 5000
    };
  }

  get(key: string): any {
    return this.config[key];
  }
}

// Export a single instance
export const configService = new ConfigService();

// Usage in other files
import { configService } from './config';
console.log(configService.get('apiUrl'));

Associated Tools and Frameworks

  • InversifyJS - Dependency injection container for TypeScript with singleton scope support
  • TSyringe - Lightweight dependency injection for TypeScript with decorators
  • NestJS - Node.js framework with dependency injection system and native singleton providers
  • Awilix - Performant IoC container for Node.js supporting different lifecycle scopes

Pro Tip

For scalable and testable applications, replace classic Singletons with dependency injection. Use IoC containers to manage object lifecycle with singleton scope while keeping your code decoupled and easily testable with mocks.

While Singleton is a recognized classic pattern, its use in modern architectures must be thoughtful. It remains relevant for specific cases (resource managers, caches, loggers) but should be implemented through dependency injection mechanisms to preserve code testability and long-term maintainability.

Themoneyisalreadyonthetable.

In 1 hour, discover exactly how much you're losing and how to recover it.