Classes vs. Functions in Node.js: When and Why to Use Classes

JavaScript gives you a lot of freedom when it comes to structuring and writing your code. In Node.js, you can write entire applications using just functions, or you can go with the object-oriented routes with classes. Both work, but they’re not always effective.

In this article, We will break down when and why it’s better to use classes instead of just functions in your Node.js project. If you want cleaner, more scalable, and testable code, read on.


Functions Are Great — But They Don’t Scale Alone

Let’s start with a common use case with creating a user and sending a welcome message.

Example using a function:

function createUser(name, email) {
  return {
    name,
    email,
    sendWelcomeEmail() {
      console.log(`Welcome, ${this.name}`);
    }
  };
}

const user = createUser("Alice", "alice@example.com");
user.sendWelcomeEmail();

This works fine. But if you want to extend or reuse the logic, things start to getting messy and difficult.


Classes come with Structure and Reusability

The same example using a class with cleaner and more flexible.

class User {
  constructor(name, email) {
    this.name = name;
    this.email = email;
  }

  sendWelcomeEmail() {
    console.log(`Welcome, ${this.name}`);
  }
}

const user = new User("Alice", "alice@example.com");
user.sendWelcomeEmail();

Why is this better?

  • You don’t need to recreate methods every time.
  • You can extend the classes (e.g. AdminUser extends User).
  • The code is easier to manage and scale.

Inheritance and Extensibility

Class make it simple to extend existing logic. Let’s see the example, how a Car can extend a Vehicle.

class Vehicle {
  constructor(make) {
    this.make = make;
  }

  start() {
    console.log(`${this.make} engine started.`);
  }
}

class Car extends Vehicle {
  honk() {
    console.log(`${this.make} says beep!`);
  }
}

const car = new Car("Toyota");
car.start();
car.honk();

Converting from classes with functions, would require more boilerplate and it’s not readable.


Dependency Injection Becomes Easier with Class

In real-world Node.js apps, especially when working with databases or external services, you often required to inject dependencies. For that classes make this straightforward and easy.

class UserService {
  constructor(database) {
    this.db = database;
  }

  async getUser(id) {
    return await this.db.findUserById(id);
  }
}

Now testing is a breeze,

const mockDb = {
  findUserById: async () => ({ id: 1, name: "Test" })
};

const service = new UserService(mockDb);
service.getUser(1).then(console.log);

This keeps your logic clean, decoupled, and testable.


Scalable Architecture Required Structure

As your app grows, It does the complexity. So, Classes help with:

  • Keep related code bundled (state + behavior).
  • Organize services, controllers, and models.
  • Avoid “function soup” across multiple files.

For example, in an Express app, you might have authController

class AuthController {
  constructor(authService) {
    this.authService = authService;
  }

  async login(req, res) {
    const token = await this.authService.login(req.body);
    res.json({ token });
  }
}

This is clean, testable, and extendable code— exactly what you want in a production app.


When You Shouldn’t Use Classes

Let’s be honest: not everything needs a class.

Use plain functions when:

  • The logic is stateless (e.g., formatDate(), slugify()).
  • You don’t need inheritance or encapsulation.
  • Simplicity is more important than structure.

Example:

function formatCurrency(amount) {
  return `$${amount.toFixed(2)}`;
}

No need to engineer simple logic.


Summary: When to Use Classes in Node.js

Use Classes When…Use Functions When…
You manage stateLogic is stateless
You need reusability or inheritanceYou need quick, simple logic
You’re building services/controllersYou’re writing utilities
You want easier testing via dependency injectionNo need for OOP features

In Node.js projects, classes bring structure, reusability, and scalability to your codebase. They shine when you’re working with services, models, or anything that holds state and behavior. Functions still have their place, but as your app grows, so should your architecture.

Know when to use each — that’s what separates good code from maintainable code.

Leave a Comment

Comments

No comments yet. Why don’t you start the discussion?

    Leave a Reply