If you’ve ever worked with a Node.js project, you’ve probably noticed a few files and folders that appear automatically. The most common ones are package.json, package-lock.json, and node_modules/.
At first, they can look a bit confusing or even unnecessary. But each of them has a specific purpose. Once you understand what they do, it becomes much easier to manage and maintain your project, especially if you’re working on a team or deploying your code somewhere else.
Let me break them down in the simplest way possible.
1. package.json: The Project Manifest
This file is basically a summary of your project. It tells npm (the Node package manager) which dependencies your app needs, what version it is, and a few other things like project name, description, and any scripts you might want to run.
It’s kind of like a recipe card. You’re saying, “To run this app, I need these ingredients.”
Here’s what it usually contains:
- Your app’s name and version
- A short description
- A list of dependencies (like Express, Lodash, etc.)
- Dev dependencies (for tools like ESLint, Babel, etc.)
- Scripts (so you can type
npm startinstead of a long command)
For example:
"dependencies": {
"express": "^4.18.2"
}
The ^ means it will accept newer versions as long as the major version (the first number) doesn’t change. So it’ll install versions like 4.19.0 or 4.20.1, but not 5.0.0.
You can also use ~ if you want to be more strict and only allow patch-level updates.
2. package-lock.json: The Snapshot
This file is automatically created when you install something with npm install.
While package.json is your wishlist, the lock file is more like a receipt. It records the exact versions that got installed, including any packages that your dependencies rely on.
So if express depends on five other libraries, those versions get locked down too. That way, when someone else clones your project and runs npm install, they get the exact same setup as you — no surprises.
That’s especially important in larger teams. If everyone is working with slightly different versions of a package, you might get bugs that are hard to trace.
Should you commit this file to your repo? Yes. Always. It helps keep things stable.
3. node_modules/: The Actual Packages
This is the folder where npm puts all the packages after installation.
If you run npm install express, the actual Express code ends up inside node_modules/express/. Same goes for every other package and its dependencies.
This folder can get really big — and messy — but it’s essential for your project to run. That said, you should never commit it to Git. The lock file already tracks everything you need, so anyone can rebuild the folder by running npm install.
In most projects, you’ll see node_modules/ added to .gitignore, so Git doesn’t include it in version control.
Quick Recap:
| Item | What It Does |
|---|---|
package.json | Lists project metadata and the packages you depend on |
package-lock.json | Saves the exact versions installed to avoid mismatches |
node_modules/ | Stores the actual installed code for those packages |
Best Practices
- ✅ Always commit
package.jsonandpackage-lock.json - ❌ Never commit
node_modules/ - ✅ Use versioning symbols (
^,~) wisely to control upgrades - ✅ Run
npm installafter cloning a repo to install everything properly
Final Thoughts
When you’re just starting out with Node.js, it’s easy to ignore these files or let them be. But understanding them is key to avoiding future headaches — especially when working on a shared codebase or deploying to production.
They’re not just technical details. They’re the foundation for how your app installs, runs, and behaves across environments. So next time you install a package, take a moment to glance at what changes in these files — it’s a good habit that’ll pay off later.