Singleton

Share One Instance Across the Application

Singleton is the normal project lifetime for stable application collaborators. The container creates the instance once and returns the same reference on every resolution, including resolutions from child containers.

When to Use Singleton

Singleton is appropriate when one shared instance is part of the design. That includes pure stateless services, process-wide infrastructure, immutable process policy, and carefully bounded shared state. The class should either produce the same output for the same input, or deliberately coordinate access to a resource that should only have one process-level owner.

checkout_service.ts
import { Component, Inject, LoadAs } from "@noego/ioc";

@Component({ scope: LoadAs.Singleton })
export class PriceCalculator {
  total(items: Array<{ quantity: number; unitPrice: number }>): number {
    return items.reduce((sum, item) => sum + item.quantity * item.unitPrice, 0);
  }
}

@Component({ scope: LoadAs.Singleton })
export class CheckoutService {
  constructor(
    @Inject(PriceCalculator) private prices: PriceCalculator,
  ) {}

  quote(items: Array<{ quantity: number; unitPrice: number }>): number {
    return this.prices.total(items);
  }
}

Good Singleton Candidates

Stateless domain services

Formatters, validators, calculators, readers, repositories, and orchestration services are safe to share when all changing data arrives through method parameters.

Shared infrastructure handles

Database runners, connection pools, process managers, event buses, schedulers, and tool registries often represent one process-level resource that the whole app should coordinate through.

Process-level policy and configuration

Feature policy readers, model/default settings, environment readers, and immutable configuration services fit singleton when they describe the running process rather than one request.

Bounded shared state

Caches, memoizers, indexes, and subscription hubs can be singleton when sharing the state is intentional, memory is bounded, and callers do not depend on request-specific values being stored inside the instance.

What Not To Store in Singletons

A singleton lives for the lifetime of the container tree. If it holds the current user, request ID, tenant, conversation, job, or any request-scoped value, the first resolution that touches it can capture that value and every later caller may see the wrong one. Use scoped state for request-specific data.

Rules

  • Use Singleton as the project default for stateless services, stable infrastructure, process policy, and intentionally shared bounded state.
  • Always specify the scope explicitly — the @Component library default is transient.
  • Singleton instances are shared across the entire container tree, including child containers created with extend().
  • Do not hold mutable request-specific state in singletons.
  • Pass changing data into method parameters and return results instead.
NoEgo

© 2025 NoEgo. All rights reserved.