NodeJSCore Modules Overview

Core Modules Overview

Core modules (also called built-in or standard-library modules) ship inside the Node binary. They need no npm install, no node_modules, and no network — they are always available the instant Node runs. They cover the fundamentals an operating system gives a program: files, networking, cryptography, streams, paths, processes, and more.

The node: prefix

Modern Node lets you import built-ins with an explicit node: prefix. Make it a habit — it is unambiguous, slightly faster to resolve, and cannot be shadowed:

JS
import fs from 'node:fs/promises'
import path from 'node:path'
import { createServer } from 'node:http'

// Still works without the prefix, but the prefix is preferred:
const os = require('node:os')
Why the prefix is worth it
`require('node:fs')` can *only* mean the built-in — it skips the `node_modules` search entirely, so a package maliciously (or accidentally) named `fs` can never intercept it. Some newer built-ins, like `node:test` and `node:sea`, are *only* importable with the prefix. It also signals intent to readers and tooling at a glance.
The standard library map

Need

Module

Covered in

File paths

node:path

OS & machine info

node:os

Debugging & formatting

node:util

Parsing/building URLs

node:url

Query strings

node:querystring

Hashing & encryption

node:crypto

Event emitters

node:events

Filesystem

node:fs

HTTP servers/clients

node:http

HTTP section

Streaming data

node:stream

Streams section

Three properties that make them special
  • Zero install — they live in the binary, so they are available offline and add nothing to node_modules.

  • Highest resolution priority — a bare specifier checks core first, so a built-in can never be accidentally shadowed by a package (see Core, Local & Third-Party Modules).

  • Version-locked to Node — their behavior is tied to your Node version, so engines.node in package.json effectively pins their feature set.

Discovering what is available

Node exposes the full list of built-in module names programmatically — handy for tooling and for checking whether a name is core:

JS
import { builtinModules } from 'node:module'

console.log(builtinModules.length)        // ~70+ modules
console.log(builtinModules.includes('fs')) // true
76
true
Stability: not all built-ins are equal
Check the stability index before relying on a built-in
Node documents each API with a *stability index*: **Stable** (safe), **Experimental** (may change without a major version — e.g. parts of `node:test`, `node:sqlite`), and **Legacy/Deprecated** (avoid — e.g. the old `url.parse()`, `domain`). Experimental APIs often print a runtime warning and can break between minor releases. Read the warning, and pin your Node version if you depend on one.
Sync, callback, and promise flavors

Many I/O-oriented core modules expose the same operation in multiple styles. fs is the canonical example — pick the promise-based subpath for modern async code:

JS
import { readFileSync } from 'node:fs'          // blocking
import { readFile } from 'node:fs'               // callback-style
import { readFile as readFileP } from 'node:fs/promises'  // promise-based ✓

The trade-offs between these styles are central to Node and are covered in Sync vs Async vs Promises API.

Next
Start with the one you'll use in almost every script — cross-platform file paths: [The path Module](/nodejs/path-module).