Code Modularization β File Separation and Structural Organization
After completing this topic:
You will understand why code should be divided into multiple files and be able to directly separate files using Node.js's require/module.exports pattern.
Why shouldn't you put everything in one file?
When a project is small, you can put all the code in one file, such as app.js. However, when the code exceeds 500 or 1000 lines, problems arise.
- Difficult to find: "Where was the login logic?" β You have to scroll down a long way.
- Conflicts: When multiple people modify the same file, git merge conflicts occur frequently.
- Cannot be reused: If you want to use a utility function created in project A in project B, you have to copy and paste it.
Modularization solves these problems. It is about separating code into one file = one role.
Separating files in Node.js
Node.js exports using module.exports and imports using require().
// math.js β Calculation utility module
function add(a, b) {
return a + b;
}
function multiply(a, b) {
return a * b;
}
module.exports = { add, multiply };// app.js β Use it in the main file
const math = require('./math');
console.log(math.add(3, 5)); // 8
console.log(math.multiply(4, 7)); // 28math.js only handles calculations. app.js only uses the function, and it doesn't need to know the calculation logic. This is the principle of separation of concerns.
Practical folder structure
As the scale increases, you organize it into folders. The following is a typical structure for an Express project.
project/
βββ app.js # Entry point β Starts the server
βββ routes/
β βββ users.js # Routes related to /users
β βββ posts.js # Routes related to /posts
βββ controllers/
β βββ userController.js
β βββ postController.js
βββ models/
β βββ db.js # Database connection
βββ utils/
βββ helpers.js # Common utility functionsroutes/ handles URL paths, controllers/ handles business logic, and models/ handles data processing. Since each folder takes on one role, if a "user-related bug" occurs, you only need to look at routes/users.js and controllers/userController.js.
ES Modules β Modern syntax
In Node.js 14+ or browsers, you can use the import/export syntax (ES Modules).
// math.mjs (or set "type": "module" in package.json)
export function add(a, b) {
return a + b;
}
export function multiply(a, b) {
return a * b;
}// app.mjs
import { add, multiply } from './math.mjs';
console.log(add(3, 5)); // 8
console.log(multiply(4, 7)); // 28require and import have the same purpose, but import allows for static analysis, so bundlers (Webpack, Vite) can remove unnecessary code (tree-shaking). ES Modules are recommended for new projects.
Key takeaways
| Question | Answer |
|---|---|
| Why separate? | Easier to find, reusable, reduces collaboration conflicts |
| How to separate? | module.exports + require (CommonJS) or export + import (ESM) |
| Criteria? | One file = one role (separation of concerns) |
| Folder structure? | Role-based classification such as routes / controllers / models / utils |
It is best to start practicing file separation when the code is 100 lines long. If you wait until the code is 1000 lines long and then try to separate it, it will already be messy and painful.