Singleton (Creational)
Intent / problem it solves
Guarantee at most one instance of a type and provide a global access point. Useful for shared configuration, logging facades, or connection pools when you truly need a process-wide instance.
When to use / when NOT
Use when a single shared resource must coordinate access (with care around threading) and hiding construction behind one accessor simplifies callers.
Avoid when it hurts testability (global mutable state), hides dependencies, or when dependency injection of a single shared instance is clearer. Prefer scoped singletons (per container / per request) over true globals.
Structure
One type owns its instance (lazy or eager), exposes GetInstance (or language equivalent), and blocks duplicate construction.
Go example
package main
import (
"fmt"
"sync"
)
type ConfigRegistry struct {
mode string
}
var (
once sync.Once
shared *ConfigRegistry
)
func Instance() *ConfigRegistry {
once.Do(func() {
shared = &ConfigRegistry{mode: "production"}
})
return shared
}
func main() {
first := Instance()
second := Instance()
fmt.Println(first == second, first.mode)
}JavaScript example
class AuditTrail {
constructor() {
if (AuditTrail.instance) {
return AuditTrail.instance;
}
this.entries = [];
AuditTrail.instance = this;
}
log(message) {
this.entries.push(message);
}
}
const trailA = new AuditTrail();
const trailB = new AuditTrail();
trailA.log('boot');
console.log(trailA === trailB, trailB.entries.length);Interview phrase
“I’d avoid a heavy global singleton unless we need true process-wide coordination; I prefer injecting a single shared instance so tests can swap fakes, and I’d use sync.Once in Go or a DI container for thread-safe lazy init.”
Related LLD case studies
Pair with any design that exposes one coordinator (e.g. resource manager, connection broker). When you add LLD docs under LLD case studies, link the concrete class that owns shared lifecycle there.
Last updated on
Spotted something unclear or wrong on this page?