What they are, why they always show up together, and how you actually use them — explained without jargon, with hands-on notes you can try.
By Majid Mazouchi
Start here
Node.js lets you run JavaScript on your computer instead of only inside a web browser. npm is the tool that fetches and manages the reusable code packages your project depends on. They ship together: install one, you get both.
Think of building a car. Node.js is the engine — the thing that actually runs your code. npm is the parts store — where you grab pre-built components instead of machining every bolt yourself. You need the engine to drive, and the store to avoid building everything from scratch.
The runtime
JavaScript was born in 1995 with exactly one job: making web pages interactive inside a browser. The browser contained the "engine" that understood the language. If you didn't have a browser open, JavaScript had nowhere to run.
In 2009, Node.js changed that. It took Google Chrome's JavaScript engine (called V8) and wrapped it so it could run directly on your machine — no browser required. Suddenly the same language used for buttons and animations could power web servers, command-line tools, build scripts, and automation.
A runtime is just "the environment that executes your code." Node.js is the runtime for JavaScript outside the browser. That's the whole idea.
The package manager
npm stands for Node Package Manager. A "package" is simply a bundle of someone else's code — a library — that solves a common problem so you don't have to. Want to build a web server, parse dates, or talk to a database? Someone has likely already written and shared a package for it.
npm has two parts worth knowing. First, the command-line tool on your computer (the npm command). Second, the registry — a giant public online warehouse holding millions of packages. When you run an install command, the tool downloads the package from the registry into your project.
package.json. It's the project's "table of contents" — it lists your dependencies (which packages, which versions) and handy shortcut commands. Commit it to version control and anyone can rebuild your exact setup with one command.
A 60-second hands-on tour
Here's the typical first encounter. After installing Node.js (which bundles npm), you'd open a terminal and do something like this:
In that flow, npm set up the project and fetched the dayjs library, while Node.js actually executed your app.js file. That division of labor — npm manages the building blocks, Node runs the result — is the heart of the relationship.
node_modules folder. It can get large and should not be committed to git — add it to .gitignore. The package.json plus package-lock.json are enough to recreate it anywhere with npm install.
When you confuse the two
| Node.js | npm | |
|---|---|---|
| What it is | A runtime that executes JavaScript | A package manager + online registry |
| Its job | Runs your code | Installs & manages code others wrote |
| You type | node app.js | npm install ... |
| Analogy | The engine | The parts store |
| Comes from | Install it yourself | Bundled inside Node.js |
People say "I'm building a Node app" and "I npm-installed a library" — and both refer to the same project. Node is the where it runs; npm is the how I got the pieces. Alternatives exist too: yarn and pnpm are other package managers that talk to the same npm registry.
From idea to running code
The fastest way for it all to click is to see Node actually do something. Below is a complete, working web server — no extra packages needed, just Node itself. Save it as server.js:
Then run it:
Open that address in a browser and you'll see your message. In about ten lines, Node has done something a browser alone never could: served a web page from your own machine. Now the second half — adding a package with npm:
Here require('dayjs') pulls in the package npm downloaded — code you didn't write, working instantly inside the program Node runs.
The dozen commands of week one
You can go a long way with just these. Keep them handy:
package.json with default settings.package.json.package.json.package.json.npx is the one people miss. It lets you run a tool a single time — say, scaffolding a new project with npx create-react-app myapp — without cluttering your machine with a global install you'll never touch again.
Two kinds of "stuff my project needs"
Open any package.json and you'll see two lists. The distinction is simpler than it looks: it's about when a package is needed.
| dependencies | devDependencies | |
|---|---|---|
| Needed | While the app runs | Only while you build/test |
| Examples | A web framework, a date library | Test runners, linters, bundlers |
| Install flag | npm install pkg | npm install pkg -D |
| Ships to production? | Yes | No |
The point is to keep your shipped application lean: tools you only use at your desk don't need to travel to the server where the app actually runs.
What ^1.2.3 actually means
npm packages use semantic versioning — three numbers, MAJOR.MINOR.PATCH, each signaling a different kind of change:
The symbol in front of a version tells npm how much wiggle room it has when updating. ^1.2.3 (caret) allows any newer minor or patch — so up to but not including 2.0.0. ~1.2.3 (tilde) is stricter, allowing only newer patches. A bare 1.2.3 means exactly that version.
npm install on different days could get slightly different versions. The package-lock.json file solves it by recording the exact version of every package actually installed — so everyone, and every server, gets a byte-for-byte identical setup. Always commit it to git.
Choosing the right tool
Node's non-blocking design makes it excellent at juggling many simultaneous, lightweight operations. It's less suited to grinding through heavy, single-threaded computation — for that, languages like C++, Rust, or Python (with native libraries) often fit better.
| Great fit | Poor fit | |
|---|---|---|
| Web APIs & servers | Heavy CPU number-crunching | |
| Real-time apps (chat, live updates) | Large-scale scientific computing | |
| Command-line tools & build scripts | Long blocking computations |
You rarely use raw Node for big projects. Instead you build on frameworks written on top of it: Express and Fastify for APIs, Next.js for full web applications. These are all just npm packages — which is exactly why the two tools in this monograph matter so much.
The loops everyone trips on
node_modules folder to git?.gitignore. Commit package.json and package-lock.json instead — together they let anyone recreate it with npm install.node_modules so enormous?node app.js). npm fetches and manages the packages your code uses (npm install ...). The engine versus the parts store.-g)?npx to skip installing at all.npm audit reports known issues in your dependency tree; many are low-severity or in dev-only tools. Read before acting, and avoid blindly running npm audit fix --force, which can break things.Official, trustworthy sources
node -v and npm -v to confirm both are ready.