Singleton in Dart — When to Use It (and When Not)
Singleton in Dart explained: factory constructor vs static instance, when one instance is right, testability traps, and DI as the better alternative.
"How do you build a singleton in Dart?" is one of the oldest Flutter questions on Stack Overflow — and it's still asked in 2026, because every app eventually needs something that exists exactly once: a logger, an analytics client, a config object. The singleton in dart pattern is easy to write and easy to misuse, so this guide covers both halves: how to create a singleton in Dart , and when you shouldn't. What you'll learn Two ways to write a dart singleton : factory constructor vs static instance Lazy vs eager initialization in Dart singletons When one instance is exactly right (loggers, config, API clients) Why singletons are hard to test — and the resettable pattern The flutter singleton vs get_it decision: DI as the alternative Whether Dart singletons are shared across isolates Step 1 — Singleton in Dart: the Factory Constructor The idiomatic dart singleton factory constructor approach uses a private named constructor plus a factory that always returns the same instance: class Logger { // The single shared instance, created lazily on first access static final Logger _instance = Logger._internal(); // The factory constructor: always returns _instance factory Logger() => _instance; // Private named constructor: nobody else can instantiate this Logger._internal(); void log(String message) { print('[LOG] $message'); } } void main() { final a = Logger(); final b = Logger(); print(identical(a, b)); // true — same object } Why this works: factory constructors don't have to create a new object — they can return an existing one. The private Logger._internal() constructor prevents Logger() from being called in any other way, so every caller gets the same instance. The static final field is initialized lazily: Dart creates it on first access, not…