What Are npm and package.json? A Beginner's Guide
Every JavaScript project has a package.json and a giant node_modules folder, and AI tools run npm commands constantly. What packages are, what npm install actually does, what the lockfile is for, and the handful of commands and warnings you need to understand.
Open almost any web project — including one built by an AI tool — and you'll find a file called package.json, another called package-lock.json, and a folder called node_modules with thousands of files in it. Your AI tool keeps running npm install. What is all this?
Packages: code other people wrote
Nobody builds an app from scratch. Want to handle dates? Process payments? Draw charts? Someone has already written that code and shared it as a package (also called a library or dependency).
npm is two things:
- A giant online registry of JavaScript packages — millions of them.
- A command-line tool that downloads the packages your project needs.
(You may also see pnpm, yarn, or bun — alternative tools that do the same job. The ideas are identical.)
package.json: your project's shopping list
package.json describes your project. The most important parts:
{
"name": "my-app",
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"next": "^16.0.0",
"react": "^19.0.0",
"stripe": "^18.0.0"
},
"devDependencies": {
"typescript": "^5.6.0"
}
}
scripts— shortcuts.npm run devruns whatever is listed underdev. This is how you start, build, and test the app.dependencies— packages your app needs to run.devDependencies— packages only needed while building and developing (like testing tools). Some hosts skip these in production, so if the app needs a package to run, it belongs independencies.
The ^ in versions means "this version or a compatible newer one."
node_modules: where packages actually live
When you run npm install, npm reads package.json, downloads every package listed — and every package those packages need, and so on — into the node_modules folder. That's why it's huge: a project with 20 dependencies can easily have hundreds of packages in node_modules.
Three rules:
- Never edit files in
node_modules. Your changes will be wiped next install. - Never commit it to git. It's listed in
.gitignorefor a reason. Anyone can recreate it withnpm install. - When in doubt, delete it and reinstall. A surprising number of weird errors disappear after deleting
node_modulesand runningnpm installagain.
package-lock.json: the exact receipt
package.json says "React 19 or a compatible newer version." The lockfile (package-lock.json) records exactly which version of every package was installed — including all the hidden ones.
That matters because it makes installs repeatable: your laptop, your teammate's, and the server all get exactly the same code. Commit the lockfile to git. Many "works on my machine but not on the server" bugs come from a missing lockfile. (Why Does My App Work Locally but Not in Production?)
The commands you'll use
npm install # install everything in package.json
npm install stripe # add a new package (and record it in package.json)
npm uninstall stripe # remove a package
npm run dev # run the "dev" script
npm run build # run the "build" script
npm ci # clean install exactly from the lockfile (used on servers)
npm outdated # list packages with newer versions available
Warnings that look scary
npm WARN deprecated ... — one of your packages (or a package it uses) is no longer maintained. Usually not urgent; worth noting.
X vulnerabilities (Y moderate, Z high) — npm checks packages against a list of known security problems. Many reported issues are in development tools and don't affect your live app, but don't ignore them forever. npm audit shows details. Be careful with npm audit fix --force — it can make breaking upgrades. (How to Update Your App's Dependencies Safely.)
ERESOLVE unable to resolve dependency tree — two packages want incompatible versions of a third. Paste the full error into your AI tool; it's usually solvable.
Packages are trust decisions
Every package is code written by someone you don't know, running with your app's permissions — and many packages can run scripts during installation. Most are fine. Some aren't:
- Check a package exists and is popular before installing something unfamiliar. Look at its page on npmjs.com: weekly downloads, last update, and whether it's the well-known one or a lookalike.
- Watch for invented names. AI tools sometimes suggest packages that don't exist — and attackers register those names hoping someone installs them. If you've never heard of a package the AI wants, check it first.
- Fewer is better. Every dependency is something that can break or be compromised. (How to Run AI-Generated Code Safely goes deeper.)
Python and others have the same idea
If your project is Python, the equivalents are pip or uv and a requirements.txt or pyproject.toml. Ruby has gems and a Gemfile; PHP has Composer. Different names, same concepts: a list of packages, a tool to install them, and a lockfile to keep everyone in sync.
EasySpawn workspaces have npm, pnpm, bun, pip, and friends ready to go, and keep your installed dependencies on persistent storage — so npm install doesn't start from zero every session. See how it works or join the waitlist.
Related: The Terminal for Complete Beginners · What Is a Framework? · Semantic Versioning Explained · What Is Node.js?
Keep reading
How to Write Good Commit Messages (and Why It Matters With AI)
'fix', 'update', and 'wip' tell you nothing six months later. What a commit message is for, the simple format most teams use, examples of good and bad messages, how often to commit when an AI tool is making the changes, and how to get Claude Code to write useful ones.
How to Write a README for Your Project
The README is the front page of your project — for collaborators, clients, future you, and AI tools that read it for context. What to include, a template you can copy, how it differs from a CLAUDE.md, and the mistakes that make READMEs useless.