How to Install Packages from npm: A Complete Guide
npm (Node Package Manager) is the default package manager for Node.js and one of the largest software registries in the world. Whether you're pulling in a utility library, a framework, or a build tool, understanding how npm installation works — and what affects it — will save you hours of debugging and configuration headaches.
What npm Actually Does When You Install a Package
When you run an npm install command, npm does several things at once. It contacts the npm registry (or a configured private registry), resolves the dependency tree for the package you requested, downloads the package and all its dependencies, and places everything inside a node_modules folder in your project directory.
It also reads and writes to two important files:
package.json— lists your project's direct dependencies and metadatapackage-lock.json— locks the exact versions of every installed package, including nested dependencies
These files matter because they're what allow someone else to clone your project and reproduce the exact same environment.
Prerequisites Before You Install Anything
You need Node.js installed on your machine before npm is available. npm ships bundled with Node.js, so installing Node gives you both. You can verify both are present by running:
node -v npm -v If either command returns a "not found" error, you'll need to install Node.js first from the official Node.js website. Most developers use either the LTS (Long Term Support) version for stability or the Current version for the latest features.
The Core Installation Commands
Installing a package locally (most common)
npm install package-name This installs the package into the node_modules folder of your current project directory. It also adds the package to the dependencies section of your package.json. Local installs are the standard approach for anything your project actually uses.
Installing as a dev dependency
npm install package-name --save-dev Use this flag for tools that only run during development — test runners, linters, bundlers, TypeScript compilers. These go into devDependencies in your package.json and won't be included in a production build in most setups.
Installing a package globally 🌍
npm install -g package-name A global install places the package in a system-wide location, making it available as a command-line tool from any directory. This is typical for CLIs like create-react-app, nodemon, or eslint when you want to use them outside of a specific project.
Installing all dependencies from an existing project
npm install Running this command with no arguments reads your package.json and installs everything listed under both dependencies and devDependencies. This is the first command most developers run after cloning a project.
Version Control: Installing Specific Versions
npm gives you precise control over which version of a package you install:
| Syntax | What It Installs |
|---|---|
npm install pkg@latest | Most recent published version |
npm install [email protected] | Exact version 2.3.1 |
npm install pkg@^2.0.0 | Latest minor/patch in the 2.x range |
npm install pkg@~2.3.0 | Latest patch in the 2.3.x range |
Semantic versioning (semver) is the system behind these flags. Understanding the difference between ^ (caret) and ~ (tilde) matters when you need stability — caret allows minor updates, tilde restricts to patch updates only.
What Affects How npm Install Behaves
Several variables change what actually happens during installation:
Your Node.js version — some packages have peer dependency requirements tied to specific Node versions. Installing a package designed for Node 18 on Node 14 can trigger warnings or failures.
Your operating system — packages with native bindings (compiled C/C++ code) behave differently on Windows, macOS, and Linux. Some require build tools like python or make to compile on install.
Network and registry configuration — corporate environments often route npm through a private registry or proxy. If npm install hangs or throws authentication errors, the issue may be registry configuration rather than the package itself.
The package-lock.json presence — when a lockfile exists, npm installs the exact versions it specifies. Without one, npm resolves versions fresh from the registry, which can produce different results across machines.
npm version itself — behavior around peer dependencies changed significantly between npm v6, v7, and later versions. npm v7+ automatically installs peer dependencies by default; earlier versions do not.
Local vs. Global: The Practical Difference
Most package-related problems stem from confusion between local and global installs. A globally installed package isn't automatically available inside your project's code — it's only accessible as a CLI tool. If you try to require() or import a package that was installed globally rather than locally, Node.js won't find it.
The general best practice is: install locally by default, globally only for standalone CLI tools you use across many projects.
🔧 When Things Go Wrong
Common install failures usually come down to a few categories:
- Permission errors on macOS/Linux — often triggered by incorrect npm ownership on the global directory; solvable without using
sudoby configuring npm's prefix path - Peer dependency conflicts — more common after npm v7; the
--legacy-peer-depsflag can bypass strict checks when needed - Corrupted
node_modules— deleting thenode_modulesfolder andpackage-lock.json, then runningnpm installfresh, resolves many mysterious errors
The Variables That Shape Your Experience
Whether a straightforward npm install works cleanly or requires troubleshooting depends on the intersection of your Node.js version, your OS, the package's native dependencies, your registry configuration, and your existing lockfile state. A setup that works without friction on one machine may behave differently on another — not because either is wrong, but because those variables interact differently.
Understanding which of these factors apply to your environment is the starting point for diagnosing anything that doesn't install as expected.