JavaScript Design Patterns — And When You Should Actually Use Them

Published: (January 18, 2026 at 05:51 AM EST)
3 min read
Source: Dev.to

Source: Dev.to

JavaScript Design Patterns — What Really Matters for Front‑End Development

JavaScript applications grow fast — more features, more modules, more complexity. Without structure, even senior developers end up drowning in technical debt.

Design patterns help you

  • ✅ Organize code
  • ✅ Avoid duplication
  • ✅ Improve maintainability
  • ✅ Scale features safely
  • ✅ Build predictable architecture

Not every classical design pattern makes sense in JavaScript. Below are the patterns that are truly relevant to JS and are used in real‑world front‑end projects.

1. Singleton Pattern

What it is
A pattern that ensures only one instance of an object exists.

Example

class AuthService {
  constructor() {
    if (AuthService.instance) return AuthService.instance;
    this.user = null;
    AuthService.instance = this;
  }
}

When to use

  • Auth manager
  • Theme manager
  • App configuration
  • Global caching layer

Real‑world use
Your React/Angular app shouldn’t create multiple authentication handlers. A singleton guarantees a single source of truth for the user session.

2. Module Pattern

What it is
Encapsulates private logic and exposes only what’s needed.

Example

const Cart = (() => {
  let items = [];
  function add(item) { items.push(item); }
  function get() { return items; }
  return { add, get };
})();

When to use

  • Utility helpers
  • Data services
  • Local‑storage wrappers
  • Analytics modules

Real‑world use
A storageService shouldn’t expose internal keys or prefixes. The module pattern keeps those details private while providing a clean public API.

3. Observer Pattern

What it is
Allows one object to notify multiple listeners when something changes.

Example

class Observable {
  constructor() { this.subscribers = []; }
  subscribe(fn) { this.subscribers.push(fn); }
  notify(value) { this.subscribers.forEach(fn => fn(value)); }
}

When to use

  • Event systems
  • UI updates
  • Real‑time data streams
  • Pub‑sub based apps

Real‑world use

  • UI state updates in vanilla JS
  • Notification centers
  • WebSocket live updates
  • Custom event emitters in React, Vue, or Node.js

4. Factory Pattern

What it is
Creates objects without exposing the creation logic.

Example

function createUser(type) {
  if (type === "admin") return { role: "admin", canDelete: true };
  return { role: "user", canDelete: false };
}

When to use

  • Conditional object creation
  • Multiple API versions
  • Data adapters

Real‑world use
Payment integrations (Stripe, PayPal, Razorpay) return different response shapes. A factory normalises them into a common interface for the rest of the app.

5. Strategy Pattern

What it is
Defines interchangeable algorithms and selects one dynamically.

Example

const feeStrategies = {
  credit: amt => amt * 0.02,
  upi:    amt => amt * 0,
  debit:  amt => amt * 0.01,
};

function calculateFee(method, amount) {
  return feeStrategies[method](amount);
}

When to use

  • Dynamic business logic
  • Replacing long if‑else chains
  • Pricing or discount calculations

Real‑world use

  • Payment fee calculation
  • Sorting functions for lists
  • Feature‑toggle based behaviour

6. Decorator Pattern

What it is
Wraps a function or object to extend behaviour without modifying the original code.

Example

function withLog(fn) {
  return (...args) => {
    console.log("Running", fn.name);
    return fn(...args);
  };
}

When to use

  • Logging
  • Caching
  • Throttling / Debouncing
  • Authorization wrappers

Real‑world use

  • React higher‑order components (withAuth)
  • Axios interceptors
  • Performance‑measurement wrappers

7. Proxy Pattern

What it is
Intercepts interactions with an object.

Example

const user = { name: "Ani" };

const proxy = new Proxy(user, {
  get(target, prop) {
    console.log("Access:", prop);
    return target[prop];
  }
});

When to use

  • Validation
  • Access control
  • Reactivity
  • Memoization

Real‑world use
Vue 3’s entire reactivity system is built on Proxy.

8. Command Pattern

What it is
Encapsulates actions as objects (execute + undo).

Example

class Command {
  constructor(execute, undo) {
    this.execute = execute;
    this.undo = undo;
  }
}

When to use

  • Undo/redo functionality
  • History tracking
  • Macro actions

Real‑world use

  • Figma undo stack
  • VS Code command palette
  • Browser‑like navigation history

9. Adapter Pattern

What it is
Converts an incompatible interface to a usable one.

Example

function axiosToFetch(response) {
  return {
    status: response.status,
    data:   response.data,
  };
}

When to use

  • Migrating codebases
  • Integrating third‑party APIs
  • Normalising inconsistent data

Real‑world use
Wrap axios responses into a unified format so your API

Back to Blog

Related posts

Read more »