JavaScriptnpm Basics

npm Basics

npm is the package manager that ships with Node.js. It downloads libraries from the public registry, records the exact versions in package.json and package-lock.json, runs scripts you've defined, and lets you publish your own packages. Yarn, pnpm and Bun are alternative clients that use the same registry — once you know npm, you mostly know them all.

Starting a project

Inside an empty directory:

Bash
npm init           # asks questions, writes package.json
npm init -y        # accept all defaults
npm init react-app my-app    # use a "create-*" starter

package.json is the manifest. It lists your project's metadata, dependencies, scripts and configuration. Every npm command reads it.

Installing dependencies

Bash
npm install lodash             # adds to "dependencies"
npm install --save-dev jest    # adds to "devDependencies"  (short: -D)
npm install -g typescript      # global install (a tool on your PATH)

npm install                    # install everything in package.json
  • dependencies — packages your code needs at runtime in production.

  • devDependencies — only needed for development: test runners, bundlers, type definitions, linters.

  • peerDependencies — packages your package expects the host project to provide (common for plugins).

  • optionalDependencies — install attempts are made but failures are ignored.

Uninstalling

Bash
npm uninstall lodash
npm uninstall -D jest
npm uninstall -g typescript
Version ranges — caret and tilde

A line like "react": "^18.2.0" is a range, not a fixed version. The leading character controls how flexible the range is.

  • ^1.2.3caret: allow any version compatible with 1.2.3 (no breaking change). Matches >=1.2.3 <2.0.0. The default.

  • ~1.2.3tilde: allow patch updates only. Matches >=1.2.3 <1.3.0.

  • 1.2.3 — exact: only that version.

  • >=1.2.3 <2, 1.2.x, * — explicit ranges.

Semantic versioning gives those characters their meaning: MAJOR.MINOR.PATCH — major changes are breaking, minor adds features, patch fixes bugs.

package-lock.json

The lock file records the exact tree of resolved versions for every install. Commit it. Two developers running npm install on the same lock file end up with identical node_modules — no "works on my machine" because of a sneaky minor bump.

npm ci vs npm install
In CI, prefer `npm ci` — it installs strictly from the lock file and fails if `package.json` and the lock disagree.
Scripts

The scripts field in package.json is a tiny task runner.

package.json (excerpt)

JSON
{
  "scripts": {
    "dev":   "vite",
    "build": "vite build",
    "test":  "vitest",
    "lint":  "eslint ."
  }
}

Bash
npm run dev          # named script
npm test             # short for npm run test
npm start            # short for npm run start
npm run build -- --mode staging   # everything after -- is passed through

Scripts run with ./node_modules/.bin already on PATH, so you can invoke any installed CLI by its name without writing the full path.

npx — run binaries without installing them

npx (bundled with npm) runs a CLI from a package. If the package is in your dependencies it uses the local copy; otherwise it downloads it on the fly.

Bash
npx prettier --write .          # use local prettier if installed
npx create-next-app@latest      # run a starter without globally installing
npx jest                        # local jest binary from node_modules
Updating dependencies

Bash
npm outdated         # list packages with newer versions available
npm update           # update to the latest within the range you specified
npm install lodash@latest    # upgrade past the range
Updates can be breaking
`npm update` only moves within your declared range, but a tool like `npm-check-updates` (`ncu`) bumps the ranges themselves. Read the changelog before crossing a major version.
Workspaces

Workspaces let one repo host multiple packages with one node_modules. Add a workspaces array to the root package.json and you can npm install from any sub-package.

JSON
{
  "name": "monorepo",
  "private": true,
  "workspaces": ["packages/*"]
}
Security and auditing

Bash
npm audit             # report known vulnerabilities
npm audit fix         # apply non-breaking fixes
npm audit --json      # machine-readable output for CI
  • Most vulnerabilities reported are in devDependencies and never reach production — but read each report.

  • Lock files are the difference between a one-line dependency update and a transitive surprise.

Quick reference
Install a runtime dep: `npm i name`. A dev dep: `npm i -D name`. Run a script: `npm run name`. Run a one-off CLI: `npx name`. Commit the lock file. In CI: `npm ci`.