Singleton Pattern & Module Pattern0%

Singleton Pattern & Module Pattern

Beginner12 min read•Updated: Jul 11, 2026
Study Materials

Singleton Pattern & Module Pattern in Modern JavaScript

Design patterns provide battle-tested architectural blueprints for common software engineering challenges. The Singleton Pattern and the Module Pattern are foundational creational and structural patterns in JavaScript used for state centralization, resource pooling, and namespace encapsulation.


1. The Singleton Pattern

The Singleton Pattern restricts the instantiation of a class to one single instance across the entire application, providing a global point of access.

Modern Implementation: Class-Based with Instance Guard

JavaScript
class DatabasePool {
static #instance = null;
 
constructor(connectionUri) {
if (DatabasePool.#instance) {
// Return existing singleton instance!
return DatabasePool.#instance;
}
 
this.connectionUri = connectionUri;
this.connections = [];
this.isConnected = true;
 
// Cache the single instance
DatabasePool.#instance = this;
}
 
static getInstance(uri = 'mongodb://localhost:27017/prod') {
if (!DatabasePool.#instance) {
DatabasePool.#instance = new DatabasePool(uri);
}
return DatabasePool.#instance;
}
 
query(sql) {
return `Executing "${sql}" on pool ${this.connectionUri}`;
}
}
 
// Verification:
const pool1 = new DatabasePool('db1');
const pool2 = new DatabasePool('db2'); // Ignored uri, returns pool1!
 
console.log(pool1 === pool2); // TRUE! Identical memory reference!

2. Singletons via ES Modules (Native Singleton)

Because ECMAScript Modules execute once and cache their exports, simply exporting an instantiated object makes it a native singleton with zero boilerplate:

JavaScript
// LoggerService.js
class Logger {
constructor() {
this.logs = [];
}
log(msg) { this.logs.push(msg); }
}
 
// Export single instantiated instance:
export const logger = Object.freeze(new Logger());
JavaScript
// app.js & auth.js both import logger:
import { logger } from './LoggerService.js';
// Both files receive the exact same singleton instance!

3. The Classic Module Pattern (Closure-Based)

Before native ES Modules, the Module Pattern used Immediately Invoked Function Expressions (IIFEs) and closures to simulate private state and expose a public API:

JavaScript
const CartModule = (function () {
// Private variables and functions (inaccessible from outside!)
let items = [];
const taxRate = 0.08;
 
function calculateTotal() {
const subtotal = items.reduce((sum, item) => sum + item.price, 0);
return subtotal * (1 + taxRate);
}
 
// Public API returned to consumer
return {
addItem(product) {
items.push(product);
console.log(`Added ${product.name}`);
},
getItemCount() {
return items.length;
},
getTotal() {
return calculateTotal();
}
};
})();
 
// Usage:
CartModule.addItem({ name: 'Headphones', price: 100 });
console.log(CartModule.getTotal()); // 108
// console.log(CartModule.items); // undefined! (Truly private!)

4. Comparing the Patterns

FeatureSingleton PatternModule Pattern
Primary GoalGuarantee exactly one instance exists globallyEncapsulate private state and expose clean public API
InstantiationLazily or eagerly instantiated classTypically evaluated immediately via IIFE or ESM
Ideal ForDatabase pools, WebSocket connections, state storesUtility namespaces, service controllers, widgets

Interactive Quiz

Practice Quiz

Question 1
What is the core guarantee of the Singleton Pattern?
Question 2
Why are ES Modules natural singletons in JavaScript?
Question 3
How did the traditional JavaScript Module Pattern achieve data privacy before ES2022 private fields?
Question 4
Why is Object.freeze() often called on singleton objects?
Question 5
What is a common testing criticism of the Singleton Pattern?
Next Lesson

Factory & Builder Patterns

Continue learning with hands-on practice, examples, and exercises in the upcoming topic.

Related Lessons

Practice Quiz

Test your understanding of this lesson with 5 questions. Each question has one correct answer.

PrevNext