When working with Node.js, two things you will use almost every day are npm and package.json.
If you are new to Node.js, you may have seen commands such as:
npm init
npm install express
npm install
npm uninstall express
But what exactly is npm? What is package.json? What is package-lock.json? And what is the difference between dependencies and devDependencies?
In this beginner-friendly guide, we will answer these questions and learn how npm and package.json work together in a Node.js project.
What is npm?
npm stands for Node Package Manager.
It is the default package manager commonly used with Node.js. npm allows developers to install, manage, update, and remove packages that can be used in their Node.js applications.
For example, instead of writing everything from scratch, you can install an existing package:
npm install express
npm downloads Express and makes it available to your project.
You can then use it in your application:
const express = require("express");
const app = express();
app.listen(3000);
npm is therefore an important part of the Node.js ecosystem.
What is a Package?
Before understanding npm, it is useful to understand what a package is.
A package is a collection of code that can be reused in an application.
For example, instead of implementing an entire web framework yourself, you can install Express:
npm install express
There are packages available for many different tasks, including:
- Web servers
- Database connections
- Authentication
- Validation
- File processing
- Logging
- Testing
- Date and time handling
- API development
The npm ecosystem contains a very large collection of reusable packages.
Checking the npm Version
When you install Node.js, npm is normally installed along with it.
You can check the installed npm version using:
npm -v
You can also check your Node.js version:
node -v
For example:
v22.x.x
and:
10.x.x
The exact version will depend on the Node.js installation on your computer.
Creating a Node.js Project
Let’s create a simple Node.js project.
First, create a directory:
mkdir my-node-app
Move into the directory:
cd my-node-app
Now initialize the project:
npm init
npm will ask you several questions, such as:
package name:
version:
description:
entry point:
test command:
git repository:
keywords:
author:
license:
After answering the questions, npm creates a file called:
package.json
Using npm init -y
If you don’t want to answer each question, you can use:
npm init -y
The -y option accepts the default values automatically.
This is commonly used when creating a basic project quickly.
After running:
npm init -y
you may get a package.json similar to:
{
"name": "my-node-app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
What is package.json?
The package.json file contains important information about your Node.js project.
It can contain:
- Project name
- Project version
- Description
- Entry point
- Scripts
- Dependencies
- Development dependencies
- Author information
- License information
For example:
{
"name": "my-node-app",
"version": "1.0.0",
"description": "My first Node.js application",
"main": "app.js",
"scripts": {
"start": "node app.js"
},
"dependencies": {
"express": "^5.1.0"
}
}
Let’s understand some of these properties.
The name Property
The name property specifies the name of your project.
{
"name": "my-node-app"
}
It is normally written in lowercase and can contain numbers, hyphens, and other valid package-name characters.
The version Property
The version property represents the current version of your project.
{
"version": "1.0.0"
}
Node.js projects commonly follow Semantic Versioning (SemVer).
A version such as:
1.2.3
generally represents:
Major.Minor.Patch
For example:
1.0.0— Initial release1.1.0— New backward-compatible functionality1.1.1— Bug fix
The description Property
The description property provides a short description of your project.
{
"description": "A beginner Node.js application"
}
This becomes especially useful when publishing packages.
The main Property
The main property specifies the primary entry point of a package.
For example:
{
"main": "app.js"
}
This indicates that app.js is the main entry file.
For many modern Node.js applications, the exact application startup command is instead explicitly defined in the scripts section.
The scripts Property
The scripts property allows you to define commands that can be executed using npm.
For example:
{
"scripts": {
"start": "node app.js"
}
}
You can then run:
npm start
npm executes:
node app.js
You can create multiple scripts.
For example:
{
"scripts": {
"start": "node app.js",
"dev": "node --watch app.js",
"test": "node --test"
}
}
You can run them using:
npm start
npm run dev
and:
npm test
The start and test scripts have special npm command behavior, while custom scripts are normally executed with npm run <script-name>.
Installing a Package
One of the most common npm commands is:
npm install
To install a specific package:
npm install express
After installation, npm updates your package.json.
For example:
{
"dependencies": {
"express": "^5.1.0"
}
}
npm also creates a directory called:
node_modules
The installed package and its required dependencies are stored there.
What is node_modules?
The node_modules directory contains packages installed for your project.
After running:
npm install express
your project might look like:
my-node-app/
│
├── node_modules/
├── package-lock.json
├── package.json
└── app.js
You generally should not manually modify files inside node_modules.
You also normally do not commit node_modules to Git.
Instead, the project’s dependency information is stored in package.json and package-lock.json.
What is package-lock.json?
When you install packages, npm creates a file called:
package-lock.json
This file records the exact dependency versions resolved for your project, along with dependency information.
For example, your package.json might specify:
{
"dependencies": {
"express": "^5.1.0"
}
}
The package-lock.json file records the specific versions that were resolved during installation.
This helps keep installations more consistent across different environments.
package.json vs package-lock.json
The two files have different purposes.
| package.json | package-lock.json |
|---|---|
| Describes the project | Records the resolved dependency tree |
| Lists dependencies | Records exact installed dependency versions |
| Contains project scripts | Helps reproduce dependency installations |
| Usually edited by developers | Normally managed automatically by npm |
Both files are important for most Node.js projects.
Dependencies
A dependency is a package that your application needs to run.
For example:
npm install express
This adds Express to the dependencies section:
{
"dependencies": {
"express": "^5.1.0"
}
}
Your application can then use the package:
const express = require("express");
Other examples of runtime dependencies might include database drivers, authentication libraries, or API frameworks.
Development Dependencies
Some packages are needed only while developing or testing your application.
These are called development dependencies.
You can install a package as a development dependency using:
npm install --save-dev nodemon
It will appear under:
{
"devDependencies": {
"nodemon": "^..."
}
}
For example, a testing framework or development utility may be a development dependency.
The distinction is essentially:
dependencies → needed by the application at runtime
devDependencies → needed primarily for development, testing, or build workflows
Installing a Specific Package Version
You can install a particular version of a package.
For example:
npm install express@5.1.0
This installs the specified Express version.
You can also install an older version if your project requires it:
npm install express@4
Updating Packages
To check which packages are outdated, you can use:
npm outdated
npm will show information about packages that have newer versions available.
You can update packages using:
npm update
For major-version upgrades, you should review compatibility changes rather than blindly updating everything.
Uninstalling a Package
If you no longer need a package, you can remove it with:
npm uninstall express
npm removes the package and updates the project’s dependency information.
Installing All Project Dependencies
Imagine you download a Node.js project from GitHub.
The project may contain:
package.json
package-lock.json
app.js
but it does not contain the node_modules directory.
You can install all required dependencies by running:
npm install
npm reads the dependency information and installs the required packages.
This is why you generally don’t need to share or commit the node_modules directory with your project.
Why Should You Not Commit node_modules?
The node_modules directory can become very large because packages can have their own dependencies.
Instead of committing it to Git, developers normally add:
node_modules/
to the project’s .gitignore file.
For example:
node_modules/
.env
When another developer downloads the project, they can simply run:
npm install
to install the required packages.
npm install vs npm ci
You may come across both:
npm install
and:
npm ci
npm install
Commonly used during development.
It installs dependencies and can update the lock file when needed.
npm ci
npm ci is designed for clean, reproducible installations, especially in automated environments such as CI/CD pipelines.
It relies on the lock file and installs the dependencies according to the locked dependency tree.
For example:
npm ci
This is commonly used in deployment and continuous integration workflows.
Local Packages vs Global Packages
npm packages can be installed locally or globally.
Local Installation
When you run:
npm install express
the package is installed in the current project.
It is recorded in the project’s dependency information.
This is the preferred approach for most application dependencies.
Global Installation
You can install a package globally using:
npm install -g <package-name>
Global installation makes a command-line tool available system-wide.
Global installation is more appropriate for certain CLI tools than for libraries that your application imports.
Using npm Packages in Your Application
After installing a package, you can use it in your Node.js application.
For example:
npm install express
Then:
const express = require("express");
const app = express();
app.get("/", (req, res) => {
res.send("Hello Node.js!");
});
app.listen(3000, () => {
console.log("Server running on port 3000");
});
The express package installed by npm is now being used by the application.
A Simple Node.js Project Example
Let’s create a small project from scratch.
Step 1: Create the directory
mkdir my-app
cd my-app
Step 2: Initialize npm
npm init -y
Step 3: Install Express
npm install express
Step 4: Create app.js
const express = require("express");
const app = express();
app.get("/", (req, res) => {
res.send("Welcome to My Node.js App");
});
app.listen(3000, () => {
console.log("Server running at http://localhost:3000");
});
Step 5: Start the application
node app.js
Or add a start script to package.json:
{
"scripts": {
"start": "node app.js"
}
}
Then run:
npm start
Useful npm Commands for Beginners
Here are some npm commands you will frequently use:
| Command | Purpose |
|---|---|
npm -v |
Check npm version |
npm init |
Create a package.json interactively |
npm init -y |
Create package.json with defaults |
npm install |
Install project dependencies |
npm install <package> |
Install a package |
npm install --save-dev <package> |
Install a development dependency |
npm uninstall <package> |
Remove a package |
npm update |
Update packages |
npm outdated |
Check outdated packages |
npm run <script> |
Run a custom npm script |
npm start |
Run the start script |
npm test |
Run the test script |
npm ci |
Perform a clean lock-file-based install |
Common Beginner Mistakes
When learning npm, beginners often make a few common mistakes.
1. Manually Editing node_modules
Avoid manually changing files inside node_modules.
If a package needs to be changed or updated, use npm commands.
2. Committing node_modules
Do not normally commit the entire node_modules directory to Git.
Use .gitignore instead.
3. Installing Everything Globally
Installing application libraries globally can cause version and dependency problems.
Install project dependencies locally unless there is a specific reason to install a command-line tool globally.
4. Ignoring package-lock.json
For applications, package-lock.json is normally useful because it records the resolved dependency tree and helps maintain reproducible installations.
5. Installing Packages Without Checking Them
Before adding a third-party package to your application, check its documentation, maintenance status, compatibility, and whether it is actually necessary.
npm and package.json: How They Work Together
The relationship between npm and package.json can be summarized like this:
Node.js Project
|
↓
package.json
|
↓
npm install command
|
↓
node_modules
|
↓
Packages available
to your application
For example:
npm install express
causes npm to install Express and record it as a project dependency.
Later, another developer can clone your project and run:
npm install
to install the project’s dependencies.
Conclusion
npm and package.json are fundamental parts of Node.js development.
npm is the package manager that helps you install and manage reusable packages, while package.json stores important information about your project, including its dependencies and scripts.
The most important commands to remember as a beginner are:
npm init -y
npm install <package>
npm install --save-dev <package>
npm uninstall <package>
npm update
npm outdated
npm install
npm ci
You should also become familiar with these three files/directories:
package.json
package-lock.json
node_modules/
Once you understand npm and package.json, you will be able to create Node.js projects, install third-party packages, manage dependencies, and work with existing Node.js applications much more confidently.
In the next step of your Node.js learning journey, a good topic to learn is Node.js Modules: require, exports, and module.exports, because modules are essential for organizing larger Node.js applications.

