,

5 Practical Examples of the Singleton Pattern in JavaScript

Posted by

Singletons ensure “only one instance” of something. Here are 5 real-world cases in JavaScript where that’s exactly what you need.

Singletons ensure “only one instance” of something. Here are 5 real-world cases in JavaScript where that’s exactly what you need.

Introduction: Why Do We Need Singletons?

Sometimes, you don’t want multiple copies of the same thing floating around in your app.

  • One database connection
  • One config object
  • One API client
  • One global store

That’s where the Singleton Pattern comes in:
👉 It ensures only one instance of a class/object exists, and provides a global access point to it.

In JavaScript, singletons are easy to create but powerful when used carefully.
Let’s walk through 5 practical examples that you’ll actually use in real-world apps.


1. Configuration Manager

Every app has configs: API keys, feature flags, and environment variables. You don’t want multiple versions floating around.

class Config {
constructor(settings) {
if (Config.instance) {
return Config.instance;
}
this.settings = settings;
Config.instance = this;
}

get(key) {
return this.settings[key];
}
}

// Usage
const config1 = new Config({ env: "dev", debug: true });
const config2 = new Config({ env: "prod" });

console.log(config1.get("env")); // dev
console.log(config1 === config2); // true

✅ Even though we tried to createconfig2It points to the same instance.


2. Logger Utility

Logging should be consistent across your whole app, not multiple disconnected loggers.

class Logger {
constructor() {
if (Logger.instance) {
return Logger.instance;
}
Logger.instance = this;
}

log(message) {
console.log(`[LOG] ${new Date().toISOString()}: ${message}`);
}
}

// Usage
const logger1 = new Logger();
const logger2 = new Logger();

logger1.log("App started");
logger2.log("User logged in");

console.log(logger1 === logger2); // true

✅ Both loggers share the same instance, making logs consistent.


3. Database Connection Manager

Databases don’t like 50 different connections from one app; that’s wasteful. A singleton ensures one connection pool per app.

class Database {
constructor(connectionString) {
if (Database.instance) {
return Database.instance;
}
this.connectionString = connectionString;
this.connected = false;
Database.instance = this;
}

connect() {
if (!this.connected) {
console.log("Connecting to", this.connectionString);
this.connected = true;
}
return this;
}
}

// Usage
const db1 = new Database("mongodb://localhost:27017/app");
db1.connect();

const db2 = new Database("mongodb://localhost:27017/other");
db2.connect();

console.log(db1 === db2); // true

✅ No matter how many times you “create” it, there’s only one DB connection.


4. Global Event Bus

A central place where components can publish/subscribe to events. If each module had its own bus, nothing would sync.

class EventBus {
constructor() {
if (EventBus.instance) {
return EventBus.instance;
}
this.events = {};
EventBus.instance = this;
}

on(event, fn) {
(this.events[event] || (this.events[event] = [])).push(fn);
}

emit(event, data) {
(this.events[event] || []).forEach(fn => fn(data));
}
}

// Usage
const bus1 = new EventBus();
const bus2 = new EventBus();

bus1.on("login", user => console.log("User logged in:", user));
bus2.emit("login", { name: "Ali" });

console.log(bus1 === bus2); // true

✅ A single bus ensures all components share the same event system.


5. Application State (Mini Store)

React, Vue, Angular… all use a form of global state. A singleton makes sure everyone references the same state object.

class Store {
constructor(initialState = {}) {
if (Store.instance) {
return Store.instance;
}
this.state = initialState;
Store.instance = this;
}

getState() {
return this.state;
}

setState(newState) {
this.state = { ...this.state, ...newState };
}
}

// Usage
const store1 = new Store({ count: 0 });
store1.setState({ count: 1 });

const store2 = new Store();
console.log(store2.getState()); // { count: 1 }

✅ Both references point to the same store. That’s the core idea of Redux/Vuex/MobX, simplified.


Bonus: Module Pattern in JS = Singleton

In ES modules, any exported object is effectively a singleton; it’s cached and reused everywhere.

// store.js
export const store = { count: 0 };

// file1.js
import { store } from "./store.js";
store.count++;

// file2.js
import { store } from "./store.js";
console.log(store.count); // updated value

✅ The module system itself enforces a singleton instance.


Wrapping It All Up

Here are 5 practical Singleton Pattern uses in JavaScript:

  1. Config Manager → one source of truth for settings
  2. Logger → consistent logs across the app
  3. Database Connection → single pool, fewer resources
  4. Event Bus → decoupled communication across modules
  5. Global Store → single state, shared everywhere

👉 Key takeaway: The Singleton Pattern isn’t just academic; it solves real-world problems whenever you want exactly one instance across your app.


Call to Action

👉 Which singleton example have you used before? Drop it in the comments 👇.

📤 Share this with a teammate who keeps spinning up “just another logger.”
🔖 Bookmark this for your design-pattern toolkit.

Leave a Reply

Your email address will not be published. Required fields are marked *