Skip to content
⚠️ This article was written in 2019. Some content may be outdated.

Node.js Error Handling Best Practices

There are plenty of articles on Node.js error handling best practices online, but most lack real-world experience. This article explores best practices based on actual projects.

Quick Start

Here is a practical example:

javascript
function pLimit(concurrency) {
  const queue = [];
  let active = 0;

  const next = () => {
    if (active >= concurrency || queue.length === 0) return;
    active++;
    const { fn, resolve, reject } = queue.shift();
    fn()
      .then(resolve, reject)
      .finally(() => {
        active--;
        next();
      });
  };

  return (fn) =>
    new Promise((resolve, reject) => {
      queue.push({ fn, resolve, reject });
      next();
    });
}

After rolling this pattern out across the team, the results were great — maintenance costs dropped noticeably.

Advanced Usage

This can be implemented as follows:

javascript
class EventEmitter {
  constructor() {
    this.events = new Map();
  }

  on(event, handler) {
    if (!this.events.has(event)) {
      this.events.set(event, []);
    }
    this.events.get(event).push(handler);
    return () => this.off(event, handler);
  }

  off(event, handler) {
    const handlers = this.events.get(event);
    if (handlers) {
      const idx = handlers.indexOf(handler);
      if (idx > -1) handlers.splice(idx, 1);
    }
  }

  emit(event, ...args) {
    const handlers = this.events.get(event) || [];
    handlers.forEach((h) => h(...args));
  }
}

Pay attention to the performance details in the code above and avoid unnecessary computations.

Handling Typed Errors

Always type your errors to distinguish between operational errors and programmer errors:

javascript
interface User {
  id: number
  name: string
  email: string
  role: 'admin' | 'user' | 'guest'
}

function createUser(data: Partial<User>): User {
  return {
    id: Date.now(),
    name: data.name || '',
    email: data.email || '',
    role: data.role || 'user'
  }
}

type UserKeys = keyof User  // 'id' | 'name' | 'email' | 'role'

Always handle errors at the appropriate layer — operational errors should be caught and handled gracefully, while programming errors should let the process crash so they can be fixed.

MIT Licensed