Core, Local & Third-Party Modules
Every module you import comes from one of three sources, and Node tells them apart purely by the specifier — the string you pass to require/import. Knowing which category a module is in tells you where it lives, whether it needs installing, and how it is resolved.
The three categories
Category | Specifier | Lives in | Needs install? |
|---|---|---|---|
Core (built-in) |
| Inside the Node binary | No |
Third-party |
|
| Yes ( |
Local |
| Your own project files | No |
The resolution algorithm that distinguishes them is detailed in How require() Resolves Modules.
Core modules
Core modules ship with Node — no install, no node_modules. They cover the fundamentals: filesystem, networking, crypto, streams, paths, and more. Prefer the node: prefix, which is unambiguous and slightly faster to resolve:
import fs from 'node:fs/promises' import path from 'node:path' import http from 'node:http' import crypto from 'node:crypto'
Need | Core module |
|---|---|
Files & directories |
|
HTTP server/client |
|
Hashing, encryption, UUIDs |
|
Streaming data |
|
Events |
|
OS / process info |
|
Worker threads |
|
Third-party modules
Installed from the npm registry into node_modules and recorded in package.json. Imported by bare name, resolved via the upward node_modules walk:
npm install express # downloads to node_modules, adds to package.json
import express from 'express' // package root
import { debounce } from 'lodash-es' // named export
import router from 'express/lib/router' // subpath (only if "exports" allows)Local modules
Your own files, imported by relative or absolute path. The leading ./ or ../ is what marks a specifier as local — omit it and Node thinks you mean a package:
import { toUSD } from './lib/currency.js' // local — note the './'
import express from 'express' // package — no './'Resolution priority
When Node sees a bare specifier, it checks in this order — core always wins, so you can never accidentally shadow a built-in with a package of the same name:
Bare specifier resolution order
require('something')
1. Is 'something' a core/built-in module? → use it, stop
2. Walk up node_modules looking for it → use it, stop
3. Throw: Cannot find module 'something'
require('./something') → skip core & node_modules; resolve as a pathQuick decision guide
Need a fundamental capability (files, http, crypto)? → core, no install.
Need solved functionality you do not want to build (web framework, date library)? → third-party, install and audit it.
Splitting your code into pieces? → local, imported by relative path.
Reaching for a tiny one-liner package? → consider writing it locally; fewer dependencies is fewer risks.