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 viaNotes
npm run <script>Generic
npm start / test / restart / stopBuilt-in shortcuts (no run)
npm run -- --flagForward CLI args

2. Setting Entry Point

FieldPurpose
"main"CJS entry (legacy resolution)
"module"ESM entry (bundler hint)
"exports"Modern conditional entry (preferred)
"types"TypeScript types entry

3. Specifying Dependencies

FieldUse
dependenciesRequired at runtime
devDependenciesBuild/test only
peerDependenciesHost must provide (plugins)
optionalDependenciesInstall if possible, ignore failures
bundleDependenciesBundled 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 CaseExample
Native bindings (e.g. fsevents on macOS)Skipped on other OSes
Performance-only depsFalls 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"
  }
}
BenefitDetail
EncapsulationOnly listed paths importable
Conditional resolutionDifferent files for ESM/CJS

7. Setting Module Type (type: module)

ValueEffect 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" }
}
BehaviorDetail
npm warningBy default just warns
engine-strict=true in .npmrcHard fail on mismatch

9. Using Pre and Post Scripts

HookRuns
preinstall / postinstallAround npm install
prepublishOnlyBefore publish (not on install)
prepack / postpackAround tarball creation
pre<script> / post<script>Around any custom script

10. Configuring bin for CLI Tools

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

SettingEffect
"files": ["dist", "README.md"]Whitelist published files
.npmignoreBlacklist (overrides .gitignore)
Always includedpackage.json, README*, LICENSE*

12. Setting Package Metadata

FieldUse
nameUnique on registry; can be scoped (@org/name)
versionSemVer
descriptionSearch/SEO
keywordsDiscoverability
licenseSPDX id (e.g. MIT)
repository / homepage / bugsLinks
author / contributorsPeople
fundingSponsorship URLs