← Back to list

Singleton Design Pattern in Python: Complete Guide for Real-World Backend Engineering

Learn the Singleton Design Pattern in Python with practical examples, production use cases, FastAPI integration, advantages, disadvantages…

Manohar · 2026-05-21 03:42 · 0 claps · 4.2 min read
#python-singleton-pattern #singleton-design-pattern #design-patterns-in-python #fastapi-design-patterns #creational-design-pattern
Open on Medium ↗
Wiki topics: 🌐 · Web Development

Singleton Design Pattern in Python: Complete Guide for Real-World Backend Engineering

Learn the Singleton Design Pattern in Python with practical examples, production use cases, FastAPI integration, advantages, disadvantages, scalability concerns, interview questions, and best practices.

Singleton Design Pattern in Python

Introduction

One of the most misunderstood design patterns in software engineering is the Singleton Pattern.

Some developers overuse it everywhere. Others avoid it completely.

But in real-world backend systems, the Singleton pattern solves a very practical problem:

Ensuring that only one instance of a class exists across the application.

This becomes extremely useful when working with:

  • Database connections
  • Configuration managers
  • Logging systems
  • Cache managers
  • Thread pools
  • Connection pools
  • Shared application state
  • Resource-heavy services

In this article, you’ll learn:

  • What the Singleton pattern actually is
  • Why it exists
  • How to implement it correctly in Python
  • Production-grade implementation strategies
  • FastAPI use cases
  • Common mistakes developers make
  • Scalability and testing considerations

This guide focuses on practical engineering value rather than theory.

What Is the Singleton Pattern?

The Singleton Pattern is a Creational Design Pattern that ensures:

  1. A class has only one instance
  2. A global access point exists for that instance

In simple words:

No matter how many times you create the object, you always get the same instance.

The Problem It Solves

Imagine a backend application creating:

  • Multiple database connection managers
  • Multiple logger objects writing to the same file
  • Multiple Redis connection pools
  • Multiple configuration loaders

This can lead to:

  • Memory waste
  • Resource duplication
  • Inconsistent application state
  • Race conditions
  • Performance degradation

The Singleton pattern prevents this by centralizing object creation.

Why This Pattern Exists

Some objects should exist only once because they manage shared resources.

Examples:

| Component                   | Why Singleton Helps        |
| --------------------------- | -------------------------- |
| Database Connection Manager | Prevents duplicate pools   |
| Logger                      | Ensures consistent logging |
| App Configuration           | Shared config everywhere   |
| Cache Manager               | Centralized cache access   |
| Metrics Collector           | Unified monitoring         |
| Thread Pool                 | Avoids unnecessary threads |

Without Singleton behavior, applications can accidentally create expensive duplicate resources.

Real-World Analogy

Think about a country’s central bank.

There should only be:

  • One official central authority
  • One source of truth
  • One shared controller

If every city created its own central bank independently, the system would become chaotic.

A Singleton works similarly.

Pattern Structure

The Singleton pattern usually contains:

  1. A private class-level instance holder
  2. Controlled object creation
  3. Global access method

Basic structure:

Client → Singleton Class
            ↓
      Existing Instance?
         /         \
       Yes         No
       ↓            ↓
Return Existing   Create One

UML / Architecture Diagram Suggestion

You can include a diagram showing:

FastAPI App
    ↓
ConfigManager (Singleton)
    ↓
Shared Database Pool

Step-by-Step Python Implementation

Basic Singleton Using __new__

from typing import Optional

class DatabaseConnection:
    _instance: Optional["DatabaseConnection"] = None

    def __new__(cls) -> "DatabaseConnection":
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            print("Creating new database connection instance")

        return cls._instance

db1 = DatabaseConnection()
db2 = DatabaseConnection()

print(db1 is db2)

# output :
Creating new database connection instance
True

Code Walkthrough and Understanding new

Python object creation happens in two steps: new() creates the object init() initializes it

The Singleton pattern usually overrides new() because:

It controls instance creation It can return an existing instance What Happens Internally

First call: db1 = DatabaseConnection() _instance is None New object created Stored in _instance

Second call: db2 = DatabaseConnection() Existing object returned No new object created

So: db1 is db2

returns:True

Beginner-Friendly Example

Application Configuration Manager

from typing import Optional

class AppConfig:
    _instance: Optional["AppConfig"] = None

    def __new__(cls) -> "AppConfig":
        if cls._instance is None:
            cls._instance = super().__new__(cls)

            cls._instance.environment = "production"
            cls._instance.debug = False

        return cls._instance

config1 = AppConfig()
config2 = AppConfig()

print(config1.environment)
print(config1 is config2)

# Output :
production
True

Singleton Using Decorator

This approach is cleaner and commonly asked in interviews.

from typing import Any

def singleton(cls):
    instances = {}

    def wrapper(*args: Any, **kwargs: Any):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)

        return instances[cls]

    return wrapper

@singleton
class Logger:
    pass

logger1 = Logger()
logger2 = Logger()

print(logger1 is logger2)

Singleton Using Metaclass

This is the most professional and scalable implementation.

Why Metaclass?

Because object creation itself is controlled by Python metaclasses.

from typing import Any

class SingletonMeta(type):
    _instances = {}

    def __call__(cls, *args: Any, **kwargs: Any):
        if cls not in cls._instances:
            cls._instances[cls] = super().__call__(
                *args,
                **kwargs
            )

        return cls._instances[cls]

class RedisCache(metaclass=SingletonMeta):
    def __init__(self) -> None:
        self.host = "localhost"

cache1 = RedisCache()
cache2 = RedisCache()

print(cache1 is cache2)

Why Metaclass Singleton Is Better

Advantages:

  • Cleaner architecture
  • Reusable across classes
  • Centralized logic
  • Better scalability
  • Enterprise-friendly

This is commonly used in production systems.

Advanced Production Example

Database Pool Manager

from threading import Lock
from typing import Optional

class DatabasePool:
    _instance: Optional["DatabasePool"] = None
    _lock: Lock = Lock()

    def __new__(cls) -> "DatabasePool":
        with cls._lock:
            if cls._instance is None:
                cls._instance = super().__new__(cls)
                cls._instance.initialize_pool()

        return cls._instance

    def initialize_pool(self) -> None:
        self.connections = []
        print("Initializing database pool")

    def get_connection(self) -> str:
        return "Database Connection"

Why Thread Safety Matters

Without thread safety:

Two threads may simultaneously create:

DatabasePool()

Result:

  • Multiple instances created
  • Singleton broken

Using Lock() prevents race conditions.

FastAPI Use Cases

The Singleton pattern is extremely common in FastAPI applications.

Shared Database Engine

from sqlalchemy import create_engine

DATABASE_URL = "postgresql://user:password@localhost/db"

engine = create_engine(DATABASE_URL)

Shared Application Configuration

from pydantic_settings import BaseSettings

class Settings(BaseSettings):
    app_name: str = "My API"
    debug: bool = False

settings = Settings()

This acts like a Singleton configuration object.

Dependency Injection vs Singleton

Modern FastAPI often prefers:

  • Dependency Injection
  • Application lifespan management

instead of classic Singleton implementations.

Why?

Because DI improves:

  • Testing
  • Maintainability
  • Flexibility

Advantages of Singleton Pattern

1. Controlled Resource Usage Prevents duplicate expensive objects.

2. Shared Global State Useful for:

  • Configurations
  • Logging
  • Metrics

3. Reduced Memory Usage- Only one object exists.

4. Centralized Access- Easy access across application layers.

5. Better Resource Management- Especially useful for:

  • Connection pools
  • Thread pools
  • Shared services

Disadvantages of Singleton Pattern

1. Global State Problems- Global shared state can become difficult to manage.

2. Harder Unit Testing- Singletons make mocking more difficult.

Example:

service = DatabasePool()

Hardcoded dependencies reduce testability.

3. Hidden Coupling- Classes become tightly connected to shared instances.

4. Concurrency Complexity- Thread safety becomes critical.

5. Violates Single Responsibility Principle

The class often manages both:

  • Business logic
  • Lifecycle management

When to Use Singleton Pattern

Use Singleton when:

Only one instance should exist Object creation is expensive Shared state is required Centralized resource management is needed Consistency across application is important

Good examples:

  • Logger
  • Cache manager
  • Database engine
  • Config manager
  • Metrics collector

When NOT to Use Singleton Pattern

Avoid Singleton when:

Object state changes frequently Per-request isolation is required High testability is needed Dependency Injection is better Hidden global state becomes dangerous

  • Metrics collector

메타데이터
post_id
44fdd6e7f487
slug
singleton-design-pattern-in-python-complete-guide-for-real-world-backend-engineering-44fdd6e7f487
url
https://medium.com/@manohar_001/singleton-design-pattern-in-python-complete-guide-for-real-world-backend-engineering-44fdd6e7f487
canonical_url
https://medium.com/@manohar_001/singleton-design-pattern-in-python-complete-guide-for-real-world-backend-engineering-44fdd6e7f487
author_url
https://medium.com/@manohar_001
status
ok
fetched_at
2026-06-26 21:52:29