ES modules and CommonJS
A module is a file that exposes part of its code to others. You know how import and export work from the tutorial. Node.js has two module systems: modern ES modules and the older CommonJS with require. New projects use ES modules, but CommonJS appears in older code and documentation, so you need to recognise it.
Your own module
Create the folder src and in it the file posts.js — a module with the blog's posts:
// src/posts.js
export const posts = [
{ id: 1, title: 'Hello, Node.js' },
{ id: 2, title: 'Working with files' },
];
export function findPost(id) {
return posts.find((post) => post.id === id);
}Import it in app.js in the project root:
// app.js
import { posts, findPost } from './src/posts.js';
console.log(posts.length); // 2
console.log(findPost(2).title); // Working with filesnode app.js prints 2 and the title of the second post. A path to your own module starts with ./ or ../ and must include the .js extension.
Built-in modules
Node.js built-in modules are imported by name with the node: prefix — it shows that the module is built in, not downloaded from npm:
import os from 'node:os';
import path from 'node:path';
console.log(path.extname('posts.json')); // .json
console.log(os.EOL === '\n' || os.EOL === '\r\n'); // trueos.EOL is the line ending of the current system.
CommonJS
In CommonJS you write require() instead of import and assign to module.exports instead of export:
const path = require('node:path');
function fileName(file) {
return path.basename(file);
}
module.exports = { fileName };
console.log(fileName('/data/posts.json')); // posts.jsonThis is how projects without "type": "module" in package.json and files with the .cjs extension work.
Comparison
| ES modules | CommonJS | |
|---|---|---|
| Importing | import x from '...' | const x = require('...') |
| Exporting | export, export default | module.exports = ... |
| Enabled by | "type": "module" or .mjs | Default, or .cjs |
await outside a function | Allowed | Not allowed |
| Path to your own file | Extension required | Extension optional |
Common mistake
The two systems cannot be mixed in one file. Copy a line with require from an old article into a project with "type": "module", and the program fails:
ReferenceError: require is not defined in ES module scopeReplace require with import: const fs = require('node:fs') becomes import fs from 'node:fs'. The opposite happens too: without the "type" field Node.js 22 still detects import by itself but prints a MODULE_TYPELESS_PACKAGE_JSON warning. To remove it, set the field with npm pkg set type=module.