03 - npm in Practice

📋 Jump to Takeaways

What npm Actually Is

npm is three things: a registry (where packages live), a CLI tool (what you type in the terminal), and a website (npmjs.com). When people say "npm" they usually mean the CLI.

It comes installed with Node.js. Check with:

npm --version
# 10.2.0

package.json

Every Node.js project starts with this file. It describes your project and its dependencies.

npm init -y

This creates a basic package.json:

{
  "name": "my-project",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "type": "commonjs"
}

Notice "type": "commonjs" at the bottom. That's the default. To use ES Modules (import/export), change it to "module":

{
  "type": "module"
}

The fields that matter most: name, type, scripts, dependencies, and devDependencies.

Installing Packages

# Add a dependency
npm install express
# or shorthand
npm i express

# Add a dev dependency (only needed during development)
npm install --save-dev vitest
npm i -D vitest

# Install everything from package.json
npm install

After installing, your package.json gets updated:

{
  "dependencies": {
    "express": "^4.18.2"
  },
  "devDependencies": {
    "vitest": "^1.2.0"
  }
}

Version Numbers

Versions follow semver: major.minor.patch

Version Meaning
4.18.2 Exact version
^4.18.2 Compatible with 4.x.x (minor + patch updates OK)
~4.18.2 Patch updates only (4.18.x)
* Any version (don't do this)

The ^ prefix is the default. It allows non-breaking updates.

The Lockfile

package-lock.json pins the exact version of every dependency (and their dependencies). This ensures everyone on your team gets identical installs.

# Always commit package-lock.json
git add package-lock.json

Never edit it manually. npm manages it for you.

Scripts

The scripts field in package.json lets you define commands.

{
  "scripts": {
    "dev": "vite dev",
    "build": "vite build",
    "lint": "eslint .",
    "test": "vitest run",
    "start": "node server.js"
  }
}
npm run dev      # runs "vite dev"
npm run build    # runs "vite build"
npm test         # shorthand for "npm run test"
npm start        # shorthand for "npm run start"

test and start are built-in npm commands, so they don't need run. Everything else does. npm dev won't work, you need npm run dev. There's no deep reason for this, npm just has a small list of shorthand commands (test, start, stop, restart) and everything else requires run.

npx

Runs a package without installing it globally.

# The old way: install globally, then run
npm install -g create-vite
create-vite my-app

With npx, skip the global install entirely:

npx create-vite my-app

The first time, npx downloads the package and caches it. Next time, it uses the cache but checks npm for newer versions. That's why you sometimes see "Need to install the following packages... Ok to proceed?"

npx also runs binaries from your local node_modules:

# These are the same
./node_modules/.bin/vitest
npx vitest

Global vs Local

# Local (project-specific)
npm install vitest

# Global (system-wide)
npm install -g vercel

Most packages should be local. Each project gets its own version, no conflicts.

Some tools make sense globally because you use them across all projects or outside of projects entirely:

npm install -g vercel    # Deploy from anywhere
npm install -g pm2       # Process manager for production
npm install -g nodemon   # Auto-restart during development

For everything else, use local installs or npx. Don't install things like typescript or eslint globally. Different projects may need different versions.

Useful Commands

npm outdated          # Show packages with newer versions
npm update            # Update packages to latest allowed by ^ or ~ in package.json
npm ls                # Show dependency tree
npm ls --depth=0      # Show only top-level dependencies
npm uninstall express # Remove a package
npm cache clean --force # Clear the global npm cache (~/.npm)

Key Takeaways

  • npm init -y creates a package.json, the starting point for any project
  • npm install adds dependencies, npm i -D adds dev dependencies
  • Versions use semver: ^ allows minor updates, ~ allows patch only
  • Always commit package-lock.json, it ensures consistent installs
  • Define commands in scripts, run with npm run <name>
  • npx runs packages without global install
  • Prefer local installs over global to avoid version conflicts

📝 Ready to test your knowledge?

Answer the quiz below to mark this lesson complete.

© 2026 ByteLearn.dev. Free courses for developers. · Privacy