npm and package.json Cheat Sheet

Look up the npm commands you use every day, from npm install to npm ci, and read a package.json with confidence, whether you or an AI wrote it. Learn the mental models behind semver, lock files, and modules. You can also download the information as a printable cheat sheet:

Free Bonus: npm and package.json Cheat Sheet

Get the npm and package.json Cheat Sheet (PDF), a printable reference to npm install and scripts, semver ranges, lock files and npm ci, ESM versus CommonJS, package.json metadata, and pnpm and Bun equivalents:

npm and package.json Cheat Sheet

Want a guided path instead of a reference? Start learning at realjs.com.

Project Setup

  • package.json describes your project and its dependencies
  • node_modules/ holds installed code, so keep it out of Git
  • Commit package-lock.json to Git
Language: Shell Filename: Create a Project
$ npm init -y
$ npm pkg set type=module
Language: JSON Filename: A Minimal package.json
{
  "name": "my-app",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "start": "node index.js"
  },
  "dependencies": {
    "date-fns": "^4.1.0"
  },
  "devDependencies": {
    "vitest": "^5.0.0"
  }
}

Install & Remove

  • dependencies are needed at runtime
  • devDependencies are build and test tools
  • Global installs are for command-line tools, not project code
Language: Shell Filename: Add Packages
$ npm install date-fns
$ npm install -D vitest
$ npm install [email protected]
$ npm install
Language: Shell Filename: Remove and Update
$ npm uninstall date-fns
$ npm update
$ npm outdated
$ npm ls --depth=0
Language: Shell Filename: Global Installs
$ npm install -g serve
$ npm ls -g --depth=0
$ npm uninstall -g serve

Scripts

  • Run any script with npm run <name>
  • start and test also work without run
  • pre<name> and post<name> run automatically
  • Local binaries are on the PATH in scripts
Language: JSON Filename: Define Scripts
"scripts": {
  "prebuild": "rm -rf dist",
  "build": "tsc",
  "postbuild": "echo done",
  "test": "vitest"
}
Language: Shell Filename: Run Scripts
$ npm run build
$ npm test
$ npm run test -- --watch
$ npm run
Language: Shell Filename: Run a Package Without Installing
$ npx cowsay hi
$ npx vitest --version

Semver Ranges

  • Versions are MAJOR.MINOR.PATCH
  • Majors may break, minors add, patches fix
  • ^ is the default range that npm writes
Range Allows Blocks
^1.2.3 1.2.3 to <2.0.0 2.0.0
~1.2.3 1.2.3 to <1.3.0 1.3.0
1.2.3 only 1.2.3 all else
^0.2.3 0.2.3 to <0.3.0 0.3.0
^0.0.3 only 0.0.3 0.0.4
* any version nothing
Language: Shell Filename: Save Exact Versions
$ npm install -E date-fns
$ npm config set save-exact true

Lock Files

  • package-lock.json pins every version, including nested ones
  • npm install may update the lock file
  • npm ci installs exactly what the lock file says
  • Use npm ci in CI and deploys
Language: Shell Filename: Reproducible Installs
$ npm ci
$ npm ls date-fns
$ npm explain date-fns

For audits and install-script safety, see the RealJS supply chain cheat sheet.

ESM vs. CommonJS

  • ESM uses import and export
  • CommonJS uses require() and module.exports
  • "type": "module" makes .js files ESM
  • .mjs is always ESM and .cjs is always CommonJS
Language: JavaScript Filename: ES Modules
import { readFile } from "node:fs/promises";
import pkg from "./pkg.json" with
  { type: "json" };
export const name = "app";
export default function run() {}
Language: JavaScript Filename: CommonJS
const fs = require("node:fs");
const { join } = require("node:path");
module.exports = { run };
exports.name = "app";
Language: JavaScript Filename: Mixing the Two
// In ESM, load a CommonJS package
import lodash from "lodash";

// In ESM, there is no __dirname
import.meta.dirname;   // Node 20.11+

// CommonJS can require() ESM (Node 22.12+)
const m = require("./esm.mjs");

Package Metadata

  • engines warns on the wrong Node.js version
  • exports controls what others may import
  • bin turns a file into a command
Language: JSON Filename: Engines, Exports, and Bin
{
  "engines": { "node": ">=22" },
  "exports": {
    ".": "./src/index.js",
    "./utils": "./src/utils.js"
  },
  "bin": { "mytool": "./cli.js" },
  "files": ["src", "cli.js"]
}
Language: JavaScript Filename: Make a CLI Executable
#!/usr/bin/env node
console.log("Hello from mytool");

Force a Nested Version

  • overrides replaces a dependency’s dependency
  • Use it to patch a vulnerable nested package
  • Remove it once the parent updates
Language: JSON Filename: Pin a Transitive Dependency
"overrides": {
  "is-number": "7.0.0"
}
Language: Shell Filename: Apply and Confirm
$ npm install
$ npm ls is-number
└── [email protected] overridden

pnpm & Bun

  • All three read the same package.json
  • pnpm shares one global package store
  • Bun installs very fast and runs TypeScript
  • For npm ci, pnpm uses --frozen-lockfile
npm pnpm Bun
npm i pnpm i bun i
npm i -D pnpm add -D bun add -d
npm run x pnpm x bun run x
npx x pnpm dlx x bunx x

You can download this information as a printable cheat sheet:

Free Bonus: npm and package.json Cheat Sheet

Get the npm and package.json Cheat Sheet (PDF), a printable reference to npm install and scripts, semver ranges, lock files and npm ci, ESM versus CommonJS, package.json metadata, and pnpm and Bun equivalents:

npm and package.json Cheat Sheet