NodeJSCore, Local & Third-Party Modules

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)

node:fs, path

Inside the Node binary

No

Third-party

express, lodash

node_modules/

Yes (npm install)

Local

./utils, ../lib/db

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:

JS
import fs from 'node:fs/promises'
import path from 'node:path'
import http from 'node:http'
import crypto from 'node:crypto'
Why the node: prefix is worth the habit
`require('node:fs')` can *only* ever mean the built-in — it bypasses the `node_modules` search entirely and cannot be shadowed by a (malicious or accidental) package literally named `fs`. It also makes intent obvious to readers and tooling. Some newer built-ins (like `node:test`) are *only* available with the prefix.

Need

Core module

Files & directories

node:fs, node:path

HTTP server/client

node:http, node:https

Hashing, encryption, UUIDs

node:crypto

Streaming data

node:stream

Events

node:events

OS / process info

node:os, node:process

Worker threads

node: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:

Bash
npm install express        # downloads to node_modules, adds to package.json

JS
import express from 'express'              // package root
import { debounce } from 'lodash-es'        // named export
import router from 'express/lib/router'     // subpath (only if "exports" allows)
Every dependency is attack surface
A third-party package runs with your program's full privileges, and so do *its* dependencies (transitively, often hundreds). Vet what you add, pin versions with a lockfile, and audit regularly — see [Introduction to npm](/nodejs/npm-intro) and [Dependency & Secret Security](/nodejs/dependency-security).
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:

JS
import { toUSD } from './lib/currency.js'   // local — note the './'
import express from 'express'                // package — no './'
The #1 beginner mistake
`require('utils')` (no `./`) does **not** load your local `utils.js` — Node searches `node_modules` for a package called `utils` and throws `Cannot find module`. Local files always need the relative prefix. (For stable internal aliases without `../../..`, use the `"imports"` field — see [Creating Local Modules](/nodejs/local-modules).)
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

Text
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 path
Quick 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.

Section complete
That wraps up Modules. Next, dive into the registry that powers third-party code: [Introduction to npm](/nodejs/npm-intro).