← Back to JavaScript
53

CommonJS, ESM, and Clean Backend Module Boundaries

Learn how to divide backend code into meaningful modules, understand the difference between CommonJS and ESM, and avoid dependency cycles that make Node projects harder to maintain.

📘 Theory

CommonJS and ESM Solve Similar Problems with Different Conventions

Both systems let you split code. The important part is choosing a consistent standard per project.

1

CommonJS uses `require` and `module.exports`. ESM uses `import` and `export`. Both are valid, but mixing them casually increases friction and confusion.

2

In a team setting, consistency often matters more than ideology. A clear convention reduces onboarding cost and debugging noise.

Design Modules Around Responsibilities, Not Folders by Habit

A module should answer one clear question for the rest of the system.

A healthy module usually represents a capability: users, auth, payments, validation, or notifications.

If one file needs to know too much about every other part of the app, you are not really modularizing. You are just moving code around.

  • Prefer domain-oriented names over vague labels like `helpers`
  • Keep each module responsible for one kind of behavior
  • Expose a small, intentional public surface

Watch for Circular Dependencies and Utility Swamps

The first signs of structural trouble usually appear early.

1

Circular dependencies make load order and state harder to understand. Generic utility files often become a dumping ground for unrelated logic that nobody wants to untangle later.

2

Both problems make refactors slower because you lose confidence about what depends on what.

Migrating Between Module Systems Requires a Plan

The safest migrations happen by layers, not by one giant rewrite.

1

If a project moves from CommonJS to ESM, define the target convention, update packages and entry points carefully, and migrate a coherent slice at a time.

2

Testing behavior after each step matters more than rushing toward a clean diff.

🧪 Learn by doing

Example Guided Example: Export a Domain Function with ESM Split email validation into its own module with a clear name and one responsibility.

🏁 Challenges

Challenge Challenge: Refactor a Vague Utility into a Clear Module Take generic validation logic and expose one focused function with an intentional name.

What is this?

I'm Cristian Eslava and I sometimes build websites so both you and I can learn and experiment. culTest

I made this in February 2026 to make learning easier for my students. The idea is to learn web development by practicing and to keep expanding the project with new topics, tests and challenges.

It draws inspiration from MDN, W3Schools, CodePen, Manz and many other web development references. I wanted to combine useful theory, runnable examples, challenges and the testing system I had already built for culTest. culTest

If you liked it, if you didn't, or if you want to get in touch, write to me at cristianeslava@gmail.com