~/night-wave
cd ~/signals
>Publishedby Shawn

One Instance, One Source of Truth

Learn what Singleton and single source of truth mean, how they differ, and how they can work together.

#programming#software-design#singletons#state-management

Singleton and single source of truth (SSOT) are often discussed together, but they solve different problems. A Singleton controls how many instances of something exist. SSOT identifies which place is authoritative for a piece of information.

They can be used separately or together. The easiest way to understand them is to see each idea on its own first.

What Is a Singleton?

A Singleton allows an application to create one instance of a class and reuse it wherever that shared service is needed.

Imagine an application with one logger. Instead of each part of the program creating its own logger, they all use the same instance:

class Logger {
  private static instance: Logger;

  private constructor() {}

  static getInstance(): Logger {
    if (!this.instance) {
      this.instance = new Logger();
    }

    return this.instance;
  }

  log(message: string) {
    console.log(message);
  }
}

const logger = Logger.getInstance();

The private constructor prevents other code from calling new Logger(). Every call to getInstance() returns the same logger inside that application process.

A Singleton is useful when one shared instance makes sense, such as a logger, configuration store, or connection manager. It does not create one instance across several servers or machines; each running process has its own.

What Is a Single Source of Truth?

SSOT means choosing one authoritative place for information. Other values should come from that source instead of being maintained as separate competing copies.

Consider a shopping cart. The list of items can be the source of truth, while the total is calculated from it:

const cartItems = [
  { name: "Keyboard", price: 80 },
  { name: "Mouse", price: 40 },
];

const getTotal = () => cartItems.reduce(
  (sum, item) => sum + item.price,
  0,
);

Storing and manually updating a separate total would create another value that could become incorrect when the cart changes. Calculating it from cartItems keeps one authority.

SSOT does not require a Singleton. A database record, configuration file, application state object, or list of cart items can be a source of truth without using the Singleton pattern.

How They Work Together

Startup configuration is a common place to combine both ideas:

  • Environment variables are deployment inputs read when the application starts.
  • One read-only configuration object becomes the runtime source of truth.
  • A Singleton makes that same object available throughout the process.
type Config = Readonly<{
  apiUrl: string;
  timeoutMs: number;
}>;

class ConfigStore {
  private static instance: ConfigStore;

  private constructor(readonly values: Config) {}

  static getInstance(): ConfigStore {
    if (!this.instance) {
      this.instance = new ConfigStore(Object.freeze({
        apiUrl: process.env.API_URL ?? "https://api.example.com",
        timeoutMs: 5000,
      }));
    }

    return this.instance;
  }
}

export const config = ConfigStore.getInstance();

The Singleton ensures that the process uses one ConfigStore. SSOT means the rest of the application reads config.values instead of rereading environment variables, hard-coding alternatives, or maintaining separate copies.

This example is for settings that remain fixed until the application restarts. Changing process.env inside the application affects only that running process and does not reliably persist or update other processes.

SSOT does not always mean read-only. If a setting is meant to change while the application runs, give one settings store or service controlled read and write methods, validation, and persistence. A database or shared provider may need to be the authority when several processes must see the same updates.

Using a Singleton does not automatically create a good source of truth. If unrelated code can freely change its values, it becomes uncontrolled global state. Startup configuration should normally be validated when loaded and kept read-only afterward.

When to Use Them

Use a Singleton when exactly one shared instance is appropriate and its lifetime matches the application process. Avoid it when users, requests, workspaces, or tests need independent instances.

Use SSOT whenever duplicate values could disagree. Decide which source owns the information, then derive or read other values from it.

Use them together when one shared object should act as the runtime authority. Configuration is a good example, but the main rule remains simple: Singleton controls the instance; SSOT controls the truth.