Modules and npm
ES modules in Node.js
Use import and export with explicit module configuration and Node built-in module specifiers.
8 minute lesson
Set "type": "module" in package.json, or use the .mjs extension.
import { readFile } from "node:fs/promises"
export async function loadConfig() {
const text = await readFile(
new URL('./config.json', import.meta.url),
'utf8'
)
return JSON.parse(text)
}
ES modules use the JavaScript-standard import and export syntax. Static imports are resolved and linked before the importing module evaluates, which lets tools and Node understand the dependency graph without executing arbitrary require() calls first.
Use an explicit file extension for relative imports in Node:
import { loadConfig } from './config.js'
The module type applies to .js files in the package scope. .mjs is always ES module syntax, and .cjs is always CommonJS. Avoid switching a package’s type without checking every .js entry point and tool configuration.
ES modules do not provide CommonJS globals such as require, module, or __dirname. Current supported Node releases provide import.meta.filename and import.meta.dirname for file-based modules. A URL relative to import.meta.url, as in the example, is also a portable way to locate a resource beside the module.
The node: prefix clearly identifies a built-in module. Package imports such as import fastify from 'fastify' are resolved through package metadata and node_modules.
Dynamic import() returns a promise and is useful for conditional or late loading. Top-level await is allowed in ES modules, but it delays evaluation of modules that depend on that graph, so keep startup dependencies visible.
Node supports interoperability between CommonJS and ES modules, but default and named export behavior can surprise consumers. Prefer one module system inside a small project and test the actual public entry points when crossing the boundary.
Your action is to create two ES modules, import one with its .js extension, and load a text file beside the module. Run the entry point from a different working directory to prove the resource path does not depend on process.cwd().
Lesson completed