npm install downloads and sets up the packages your project needs

When you run npm install in your project folder, npm reads a file called package.json that lists every package your project depends on. It then downloads each of those packages from the npm registry (a central repository of code libraries) and stores them in a folder called node_modules. This happens automatically — you do not manually pick and download each one.

The command also creates or updates a file called package-lock.json, which records the exact versions of every package that was installed. This matters because if someone else clones your project later, running npm install on their machine will download the same versions you used, not newer ones that might have breaking changes.

Think of package.json as a shopping list and npm install as the act of going to the store and buying everything on it. The package-lock.json is a receipt that says exactly which brand and size you bought, so you can buy the same thing again later.

Key Takeaways

  • npm install reads your package.json file and downloads all the packages listed there into a node_modules folder.
  • The command creates or updates package-lock.json to lock in the exact versions you installed, so other developers get the same setup.
  • You run npm install once when you first clone a project, and again whenever someone adds a new package to package.json.
  • The node_modules folder can be very large and is usually not stored in version control — npm install rebuilds it from package.json and package-lock.json.

Why package.json and package-lock.json exist separately

Your package.json file lists packages with version ranges, not exact versions. For example, you might specify "express": "^4.18.0", which means "version 4.18.0 or any newer version in the 4.x series." This is useful because it lets npm grab bug fixes automatically.

But this flexibility creates a problem: if you install today and someone else installs tomorrow, they might get a different version if a new patch was released. That difference can cause bugs that only happen on their machine. The package-lock.json file solves this by recording the exact version that was installed — in this case, maybe "express": "4.18.2" — so the next person gets 4.18.2, not 4.19.0.

When you commit your project to version control (like Git), you commit both files. npm install reads package-lock.json first if it exists, so it installs the locked versions. If package-lock.json does not exist, npm installs based on the ranges in package.json and creates a new lock file.

What happens inside node_modules

The node_modules folder is where npm stores all the code it downloads. If your project depends on Express, and Express depends on 15 other packages, all of those end up in node_modules. The folder can easily contain thousands of files and take up hundreds of megabytes or more.

This is why node_modules is almost never committed to version control. Instead, you add it to a .gitignore file so Git ignores it. When someone clones your project, they get package.json and package-lock.json but not node_modules. They run npm install, and npm rebuilds the entire folder from scratch in seconds.

If you ever need to clean up and start fresh, you can delete the node_modules folder entirely and run npm install again. npm will recreate it exactly as it was, using the versions locked in package-lock.json.

The difference between npm install and npm ci

For everyday development, npm install is what you use. But there is a related command called npm ci (short for "clean install") that is stricter. It refuses to run if package-lock.json does not exist, and it will not update the lock file — it only installs what is already locked.

npm ci is designed for automated environments like continuous integration servers, where you want to may provide that the exact same versions run every time, with no surprises. In development, npm install is more forgiving and is the command you will use most often.

When to run npm install

Run npm install when you first clone a project from a repository. This downloads all the dependencies so your code can actually run.

Run it again whenever someone on your team adds a new package to package.json. If you pull changes from Git and package.json has changed, running npm install will download the new packages and update package-lock.json.

You do not need to run it every time you edit your own code. Once the packages are in node_modules, they stay there until you delete the folder or change what is in package.json.

Common issues and what they mean

If you see an error like "Cannot find module 'express'", it usually means node_modules is missing or incomplete. Delete the node_modules folder and run npm install again.

If npm install takes a very long time, your internet connection might be slow, or the npm registry might be temporarily overloaded. It is safe to stop the command and try again — npm will resume where it left off.

If you see warnings about deprecated packages or security vulnerabilities, they appear after npm install finishes. These are informational and do not stop the command from working, but they are worth reading. You can run npm audit to see details and npm audit fix to update vulnerable packages.

Frequently Asked Questions

Do I need to run npm install every time I start working?

No. Run it once when you clone the project, and again only if package.json changes. Once node_modules exists, your code can find the packages it needs. If you delete node_modules by accident, run npm install to rebuild it.

What is the difference between npm install and npm update?

npm install uses the versions locked in package-lock.json. npm update checks for newer versions that match the ranges in package.json and updates both the packages and the lock file. Use npm update when you want to get bug fixes or new features from your dependencies.

Can I use npm install on a project that uses a different package manager like yarn or pnpm?

You can, but it is not recommended. Each package manager creates its own lock file format (yarn.lock, pnpm-lock.yaml). If the project was set up with yarn, use yarn install instead. Mixing them can cause version conflicts and confusion.

Why is node_modules so large?

Because packages depend on other packages, which depend on other packages. A single package you install might pull in dozens of dependencies, each with their own dependencies. npm stores all of them in node_modules so your code can find them quickly.

What happens if I manually edit package-lock.json?

Do not do this. The lock file is generated and maintained by npm. If you edit it by hand, you risk creating inconsistencies that break npm install or cause your code to use the wrong versions. If you need to change versions, edit package.json and let npm update the lock file.