Skip to content
Node.js nd core 4 min read

Node.js Core Modules Overview

Node.js ships with a rich standard library of core modules — built-in components compiled directly into the runtime that give you file system access, networking, cryptography, streams, and more without installing a single dependency. Because they live inside the runtime, they load instantly, version in lockstep with Node itself, and never appear in your node_modules folder. Understanding what is available out of the box helps you reach for the standard library before adding third-party packages.

What core modules are

A core module is part of the Node.js binary. When you import fs or http, Node resolves it internally rather than searching the file system, so there is nothing to install and nothing to bundle. They are the foundation that most npm packages are themselves built on top of.

Core modules work with both module systems. With ES modules (the modern default) you use import; with CommonJS you use require. Either way the module name resolves to the same built-in code.

// ES modules (recommended)
import { readFile } from 'node:fs/promises';

// CommonJS (legacy, still widely used)
const { readFile } = require('node:fs/promises');

The node: prefix

Modern Node.js supports an explicit node: prefix for importing built-ins, for example node:fs instead of fs. The prefix is strongly recommended: it tells Node (and human readers) unambiguously that you mean the built-in module, removing any chance that a same-named package in node_modules could shadow it. It also lets Node skip the file-system resolution step entirely.

import os from 'node:os';
import path from 'node:path';
import { createHash } from 'node:crypto';

const id = createHash('sha256').update(os.hostname()).digest('hex').slice(0, 12);
console.log(`Host fingerprint: ${id}`);
console.log(`Config path: ${path.join(os.homedir(), '.myapp', 'config.json')}`);

Output:

Host fingerprint: 9f2c1ab47de0
Config path: /home/alice/.myapp/config.json

Some modules, such as node:test and node:sea, are only importable with the node: prefix. Adopting the prefix everywhere keeps your imports consistent and future-proof.

Core modules vs npm packages

The two look similar at the call site but differ in important ways.

AspectCore modulesnpm packages
InstallationBuilt in, nothing to installnpm install required
In node_modules?NoYes
VersioningTied to your Node.js versionIndependent (package.json)
ResolutionInternal, instantFile-system lookup
Examplesfs, http, cryptoexpress, axios, zod

A practical rule: prefer a core module when it covers your need (e.g. native fetch over axios, node:test over a test framework for simple cases), and reach for npm when you need higher-level ergonomics or features the standard library does not provide.

The most important core modules

These are the modules you will use most often in real applications.

ModulePurpose
node:fs / node:fs/promisesRead, write, and watch files and directories
node:pathBuild and normalize file system paths cross-platform
node:http / node:httpsCreate HTTP(S) servers and clients
node:osQuery CPU, memory, network, and OS information
node:cryptoHashing, HMAC, ciphers, and random bytes
node:streamComposable readable/writable data pipelines
node:eventsThe EventEmitter base for event-driven APIs
node:urlParse and construct URLs and URLSearchParams
node:utilHelpers like promisify, inspect, and parseArgs
node:processEnvironment variables, argv, and lifecycle signals
node:zlibGzip, Brotli, and deflate compression
node:dnsResolve hostnames and DNS records

A quick example that combines several of them — a tiny HTTP server that reports system load:

import { createServer } from 'node:http';
import os from 'node:os';

const server = createServer((req, res) => {
  const body = JSON.stringify({
    platform: os.platform(),
    cpus: os.cpus().length,
    loadAvg: os.loadavg(),
    freeMem: os.freemem(),
  });
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(body);
});

server.listen(3000, () => {
  console.log('Listening on http://localhost:3000');
});

Output:

Listening on http://localhost:3000

Promise-based variants

Several older callback-based modules now offer a promise-based namespace that pairs cleanly with async/await. The most common is node:fs/promises, but node:dns/promises, node:timers/promises, and node:stream/promises exist too.

import { readFile } from 'node:fs/promises';

const pkg = JSON.parse(await readFile('package.json', 'utf8'));
console.log(`Project: ${pkg.name}@${pkg.version}`);

Output:

Project: [email protected]

Prefer the /promises variants in new code. They avoid callback nesting and integrate naturally with try/catch for error handling.

Best Practices

  • Always import built-ins with the node: prefix to avoid shadowing and clarify intent.
  • Reach for the standard library first — native fetch, crypto, and node:test cover many needs without dependencies.
  • Use the /promises namespaces (node:fs/promises, node:dns/promises) with async/await instead of callback APIs.
  • Use node:path for any path manipulation so your code stays correct on Windows, macOS, and Linux.
  • Pin to an active LTS release (Node 20 or 22) so the core module APIs you rely on are stable and supported.
  • Avoid naming your own files or npm packages after core modules (crypto.js, events.js) to prevent confusing resolution bugs.
Last updated June 14, 2026
Was this helpful?