Chapter 17: Node package.json
1. What is package.json really?
package.json is the identity card and configuration file of every Node.js project.
It tells:
- Who the project is (name, version, description)
- How to run it (scripts)
- What it needs to work (dependencies)
- What tools are used only during development (devDependencies)
- What kind of module system it uses (type: “module” or commonjs)
- Which Node.js version it expects (engines)
- Much more…
Almost every serious Node.js project has one — and you should never commit a project without it.
2. Creating package.json – the realistic ways
Way 1 – Quick & most common (recommended)
|
0 1 2 3 4 5 6 |
npm init -y |
→ Creates a very basic package.json instantly
Way 2 – Interactive (you answer questions)
|
0 1 2 3 4 5 6 |
npm init |
→ npm asks you many questions (you can press Enter to skip most)
Way 3 – Manual Just create an empty file called package.json and fill it yourself.
3. Real-world package.json – annotated line by line (2026 style)
This is a modern, realistic package.json for a medium-sized API project:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
{ // ────────────────────────────────────────────────────────────── // BASIC IDENTITY // ────────────────────────────────────────────────────────────── "name": "task-manager-api", // lowercase, kebab-case, unique "version": "1.2.3", // follow semver: major.minor.patch "description": "REST API for personal task management with authentication", "private": true, // prevents accidental publishing to npm "type": "module", // VERY IMPORTANT → enables ESM (import/export) // ────────────────────────────────────────────────────────────── // ENTRY POINTS // ────────────────────────────────────────────────────────────── "main": "dist/index.js", // for libraries (CommonJS entry) "module": "dist/index.mjs", // for ESM-aware bundlers "types": "dist/index.d.ts", // TypeScript declaration file // ────────────────────────────────────────────────────────────── // SCRIPTS – the most used part after dependencies // ────────────────────────────────────────────────────────────── "scripts": { "start": "node dist/index.js", // production start "dev": "nodemon --watch src -e js,ts --exec tsx src/index.ts", // development "build": "tsc && tsup", // compile TS → JS "lint": "eslint . --ext .ts,.tsx", "lint:fix": "eslint . --ext .ts,.tsx --fix", "format": "prettier --write .", "test": "vitest run", "test:watch": "vitest", "typecheck": "tsc --noEmit", "db:generate": "prisma generate", "db:migrate": "prisma migrate deploy", "db:studio": "prisma studio", "prepare": "husky install" // runs automatically after npm install }, // ────────────────────────────────────────────────────────────── // DEPENDENCIES – packages needed to RUN the app in production // ────────────────────────────────────────────────────────────── "dependencies": { "express": "^4.19.2", "zod": "^3.23.8", "dotenv": "^16.4.5", "@prisma/client": "^5.20.0", "jsonwebtoken": "^9.0.2", "bcryptjs": "^2.4.3", "cors": "^2.8.5", "helmet": "^7.1.0" }, // ────────────────────────────────────────────────────────────── // DEV DEPENDENCIES – only needed during development / building // ────────────────────────────────────────────────────────────── "devDependencies": { "@types/express": "^4.17.21", "@types/node": "^20.14.10", "@types/jsonwebtoken": "^9.0.6", "@types/bcryptjs": "^2.4.6", "typescript": "^5.5.4", "tsx": "^4.19.0", "nodemon": "^3.1.7", "prisma": "^5.20.0", "vitest": "^2.0.5", "eslint": "^9.9.0", "eslint-config-standard-with-typescript": "^43.0.1", "prettier": "^3.3.3", "husky": "^9.1.4", "lint-staged": "^15.2.10", "tsup": "^8.2.4" }, // ────────────────────────────────────────────────────────────── // OTHER IMPORTANT FIELDS // ────────────────────────────────────────────────────────────── "engines": { "node": ">=20.0.0" // protects from old Node versions }, "author": { "name": "Your Name", "email": "you@example.com", "url": "https://github.com/yourusername" }, "license": "MIT", // very important if you publish "repository": { "type": "git", "url": "git+https://github.com/yourusername/task-manager-api.git" }, // Optional – very useful for larger projects "volta": { "node": "20.17.0", "npm": "10.8.3" }, "lint-staged": { "*.{js,ts,tsx}": "eslint --fix", "*.{js,ts,tsx,json,md}": "prettier --write" } } |
4. Most important fields – explained like a senior developer
| Field | Why it matters | Common values / tips |
|---|---|---|
| name | Unique identifier – used when publishing or referencing locally | lowercase, kebab-case, no spaces |
| version | Semantic versioning – controls updates & compatibility | 1.0.0 → 1.1.0 (minor) → 2.0.0 (breaking) |
| private | Prevents accidental npm publish | true for almost all apps |
| type | “module” = ESM, no field or “commonjs” = require | Set “type”: “module” for new projects |
| scripts | Custom commands – heart of daily workflow | dev, start, build, test, lint… |
| dependencies | Runtime packages – go to production | express, prisma, zod, jsonwebtoken… |
| devDependencies | Development-only tools – not sent to production | typescript, eslint, vitest, nodemon, tsup… |
| engines | Specifies minimum Node.js version | “>=20.0.0” or “>=20.11.0 <21” |
| volta | Pins exact node & npm versions (great for teams) | Works with Volta tool – very popular |
| lint-staged | Runs linters/formatters only on staged files (pre-commit) | Used with husky |
5. Common real-world patterns & tips (2026)
- Use “private”: true → almost always for applications
- Prefer “type”: “module” + ESM syntax for new work
- Add engines field → prevents “it works on my machine” issues
- Use volta or nvmrc to lock Node version in team
- Keep devDependencies separate → reduces production bundle size
- Use descriptive scripts names — npm run typecheck, npm run db:reset, etc.
- Run npm audit regularly (security)
- Use npm ci instead of npm install in CI/CD
Summary – Quick cheat sheet of must-know fields
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
{ "name": "my-project", "version": "1.0.0", "private": true, "type": "module", "main": "src/index.js", "scripts": { "dev": "nodemon src/index.js", "start": "node src/index.js", "test": "vitest" }, "dependencies": { ... }, "devDependencies": { ... }, "engines": { "node": ">=20.0.0" } } |
Which direction would you like to go next?
- Deep dive into scripts section (real-world examples)
- How package-lock.json really works
- Semantic versioning explained with real examples
- Publishing your own package to npm
- Using volta / nvm / corepack to manage versions
- Difference between npm, yarn, pnpm in practice
Just tell me what feels most useful right now — I’ll continue with detailed examples. 😄
