What is the Module pattern?
By FrontendPro Editorial Team Updated 9/26/2026
Answer
The Module pattern uses a function scope to keep some things private and expose only a chosen public interface. Before ES modules existed, it was the standard way to avoid polluting the global namespace.
const counter = (function () {
let count = 0; // private — unreachable from outside
function validate(n) { // private helper
return Number.isInteger(n) && n > 0;
}
return { // the public interface
increment: () => ++count,
add(n) { if (validate(n)) count += n; },
get value() { return count; },
};
})();
counter.increment();
counter.count; // undefined — genuinely inaccessible
An IIFE runs once, its scope stays alive because the returned object closes over it, and everything not in that returned object is private.
The revealing variant
Define everything as normal functions, then return a map of the ones you want public. It makes the public surface visible in one place:
function createStore() {
let state = {};
function get(k) { return state[k]; }
function set(k, v) { state = { ...state, [k]: v }; }
function reset() { state = {}; }
return { get, set }; // reset stays private
}
What replaced it
ES modules do this natively. A module's top-level scope is already private, and export chooses what is public — no IIFE, no wrapper:
let count = 0; // private to this file
export const increment = () => ++count;
A module also runs once no matter how many files import it, so it is a singleton by default — the other thing the pattern provided.
When it is still relevant
In a plain <script> without a build step, in a library that must work as a global, and as the explanation for how closures create privacy. Note the factory form — a function returning an object — is the same idea, but gives a fresh private scope per call instead of one shared instance.
