Working with Package.json
1. Defining Scripts
Example: Common scripts
{
"scripts": {
"dev": "node --watch src/index.js",
"start": "node dist/index.js",
"build": "tsc -p tsconfig.json",
"test": "node --test",
"lint": "eslint .",
"format": "prettier --write ."
}
}
| Run via | Notes |
npm run <script> | Generic |
npm start / test / restart / stop | Built-in shortcuts (no run) |
npm run -- --flag | Forward CLI args |
2. Setting Entry Point
| Field | Purpose |
"main" | CJS entry (legacy resolution) |
"module" | ESM entry (bundler hint) |
"exports" | Modern conditional entry (preferred) |
"types" | TypeScript types entry |
3. Specifying Dependencies
| Field | Use |
dependencies | Required at runtime |
devDependencies | Build/test only |
peerDependencies | Host must provide (plugins) |
optionalDependencies | Install if possible, ignore failures |
bundleDependencies | Bundled inside published tarball |
4. Using Peer Dependencies
Example: Plugin requiring host
{
"name": "eslint-plugin-foo",
"peerDependencies": { "eslint": "^9.0.0" },
"peerDependenciesMeta": { "eslint": { "optional": false } }
}
Note: npm 7+ auto-installs peer deps; v8+ enforces them strictly.
5. Using Optional Dependencies
| Use Case | Example |
Native bindings (e.g. fsevents on macOS) | Skipped on other OSes |
| Performance-only deps | Falls back to JS implementation |
6. Configuring Exports
Example: Subpath + types
{
"exports": {
".": { "types": "./d.ts", "import": "./esm.js", "require": "./cjs.cjs" },
"./feature": { "import": "./esm/feature.js" },
"./package.json": "./package.json"
}
}
| Benefit | Detail |
| Encapsulation | Only listed paths importable |
| Conditional resolution | Different files for ESM/CJS |
7. Setting Module Type (type: module)
| Value | Effect on .js |
"module" | Treated as ESM |
"commonjs" (default) | Treated as CJS |
8. Defining Engines
Example: Pin engine
{
"engines": { "node": ">=20.0.0", "npm": ">=10.0.0" }
}
| Behavior | Detail |
| npm warning | By default just warns |
engine-strict=true in .npmrc | Hard fail on mismatch |
9. Using Pre and Post Scripts
| Hook | Runs |
preinstall / postinstall | Around npm install |
prepublishOnly | Before publish (not on install) |
prepack / postpack | Around tarball creation |
pre<script> / post<script> | Around any custom script |
Example: CLI binary
{
"name": "my-cli",
"bin": { "my-cli": "./bin/cli.js" }
}
Note: First line of cli.js must be #!/usr/bin/env node. After install, my-cli is in node_modules/.bin/.
11. Using Files Field
| Setting | Effect |
"files": ["dist", "README.md"] | Whitelist published files |
.npmignore | Blacklist (overrides .gitignore) |
| Always included | package.json, README*, LICENSE* |
| Field | Use |
name | Unique on registry; can be scoped (@org/name) |
version | SemVer |
description | Search/SEO |
keywords | Discoverability |
license | SPDX id (e.g. MIT) |
repository / homepage / bugs | Links |
author / contributors | People |
funding | Sponsorship URLs |