Last updated
Basic Node.js Application package.json
A minimal package.json for a Node.js web application:
{
"name": "my-web-app",
"version": "1.0.0",
"description": "A Node.js web application",
"main": "src/index.js",
"scripts": {
"start": "node src/index.js",
"dev": "nodemon src/index.js",
"test": "jest"
},
"engines": {
"node": ">=18.0.0",
"npm": ">=9.0.0"
},
"author": "Jane Doe <jane@example.com>",
"license": "MIT",
"dependencies": {
"express": "^4.18.2"
},
"devDependencies": {
"nodemon": "^3.0.1",
"jest": "^29.7.0"
}
}
TypeScript Library package.json
A package intended to be published to npm with TypeScript support:
{
"name": "my-utility-lib",
"version": "1.0.0",
"description": "A utility library with TypeScript support",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": "./dist/index.js",
"require": "./dist/index.cjs",
"types": "./dist/index.d.ts"
}
},
"files": [
"dist",
"README.md",
"LICENSE"
],
"scripts": {
"build": "tsup src/index.ts --format cjs,esm --dts",
"test": "vitest run",
"lint": "eslint src --ext .ts",
"prepublishOnly": "npm run build && npm test"
},
"keywords": ["utility", "typescript"],
"license": "MIT",
"devDependencies": {
"typescript": "^5.3.3",
"tsup": "^8.0.1",
"vitest": "^1.2.0",
"eslint": "^8.56.0"
}
}
Version Range Strategies
Understanding the three main version range operators:
{
"dependencies": {
// Caret (^) — allows minor and patch updates
// ^1.2.3 accepts >=1.2.3 <2.0.0
"express": "^4.18.2",
// Tilde (~) — allows only patch updates
// ~1.2.3 accepts >=1.2.3 <1.3.0
"lodash": "~4.17.21",
// Exact — locks to specific version
"critical-dep": "2.0.1",
// Latest — always installs newest (avoid in production)
"dev-tool": "*"
}
}
Use ^ for most dependencies (safe updates), ~ for dependencies where minor changes might break things, and exact versions for security-critical packages.
Modern ESM + CJS Dual Package
Supporting both ES modules and CommonJS with the exports field:
{
"name": "my-package",
"version": "1.0.0",
"type": "module",
"exports": {
".": {
"import": {
"types": "./dist/esm/index.d.ts",
"default": "./dist/esm/index.js"
},
"require": {
"types": "./dist/cjs/index.d.cts",
"default": "./dist/cjs/index.cjs"
}
},
"./utils": {
"import": "./dist/esm/utils.js",
"require": "./dist/cjs/utils.cjs"
}
},
"main": "./dist/cjs/index.cjs",
"module": "./dist/esm/index.js",
"types": "./dist/esm/index.d.ts"
}
React Application package.json
A Vite-based React TypeScript application:
{
"name": "my-react-app",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"test": "vitest run",
"lint": "eslint src --ext .ts,.tsx --max-warnings 0",
"format": "prettier --write src/**/*.{ts,tsx}"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.2.55",
"@types/react-dom": "^18.2.19",
"@vitejs/plugin-react": "^4.2.1",
"typescript": "^5.3.3",
"vite": "^5.1.0",
"vitest": "^1.2.0",
"eslint": "^8.56.0",
"prettier": "^3.2.4"
}
}
Repository and Publishing Fields
Fields that appear on the npm package page:
{
"name": "my-package",
"version": "1.0.0",
"description": "A helpful utility package",
"keywords": ["utility", "helper", "tools"],
"author": {
"name": "Jane Doe",
"email": "jane@example.com",
"url": "https://janedoe.example.com"
},
"contributors": [
"John Smith <john@example.com>"
],
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/example/my-package.git"
},
"bugs": {
"url": "https://github.com/example/my-package/issues",
"email": "bugs@example.com"
},
"homepage": "https://my-package.example.com",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/example"
}
}
Files Field — Controlling npm Publish Content
Specify exactly what gets published to npm:
{
"files": [
"dist", // Built output
"src", // Source (optional, for source maps)
"README.md",
"LICENSE",
"CHANGELOG.md"
]
// Automatically excluded (even without .npmignore):
// node_modules, .git, test files, .env files
}
The files whitelist approach is safer than .npmignore — you explicitly choose what to include rather than trying to exclude everything you don't want.
Peer Dependencies
For plugins and packages that require a host package:
{
"name": "react-my-component",
"peerDependencies": {
"react": "^17.0.0 || ^18.0.0",
"react-dom": "^17.0.0 || ^18.0.0"
},
"peerDependenciesMeta": {
"react-dom": {
"optional": true
}
},
"devDependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
}
Peer dependencies tell npm that the consuming project must have these packages installed. They are not installed automatically — the user is responsible for providing them.