npm Scripts and package.json Mastery (2026)
Your package.json is more than a dependency list. It is a powerful automation tool. Here is how to master npm scripts.
package.json Essentials
{
"name": "my-awesome-project",
"version": "1.0.0",
"description": "A well-configured project",
"type": "module", // Use ES modules (import/export) instead of CommonJS
"main": "./dist/index.js", // Entry point for require()
"exports": { // Control what external code can import (Node.js 12.7+)
".": {
"import": "./dist/index.js",
"require": "./dist/index.cjs"
},
"./utils": "./dist/utils.js"
},
"bin": { // CLI commands
"my-tool": "./cli.js"
},
"files": [ // Files to include when publishing
"dist",
"README.md"
],
"engines": { // Required Node.js version
"node": ">=18.0.0"
},
"scripts": { // THE POWERFUL PART (see below)
...
}
}
Script Basics
{
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js",
"build": "tsc",
"test": "jest",
"lint": "eslint src/",
"format": "prettier --write 'src/**/*.{js,ts}'"
}
}
Run with: npm run dev or shorthand npm test / npm start
Pre/post hooks run automatically:
{
"scripts": {
"prebuild": "npm run lint && npm run clean",
"build": "tsc",
"postbuild": "npm run test"
}
}
// Running `npm run build` automatically executes:
// prebuild → build → postbuild (in order)
Environment Variables in Scripts
{
"scripts": {
"dev": "NODE_ENV=development nodemon server.js",
"prod": "NODE_ENV=production node server.js",
"test": "NODE_ENV=test jest --coverage"
}
}
// Cross-platform solution (Windows compatible):
// Install cross-env: npm install -D cross-env
{
"scripts": {
"dev": "cross-env NODE_ENV=development nodemon server.js"
}
}
Advanced Script Patterns
{
"scripts": {
// Chaining with && (run sequentially, stop on failure)
"validate": "npm run lint && npm run typecheck && npm run test",
// Chaining with & (run in parallel)
"dev:all": "npm run dev:client & npm run dev:server",
// Using npm variables
"show-pkg": "echo %npm_package_name% v%npm_package_version%",
// On Unix: echo $npm_package_name v$npm_package_version
// Conditional scripts (using tiny CLI tools)
"deploy:staging": "[ \"$NODE_ENV\" = \"production\" ] && echo 'Cannot deploy from production!' || npm run deploy:staging:real",
// Script composition (call other scripts)
"ci": "npm run lint && npm run typecheck && npm run test:cov && npm run build",
// Watch mode for development
"watch": "tsc -w && nodemon dist/server.js",
// Database operations
"db:migrate": "knex migrate:latest",
"db:rollback": "knex migrate:rollback",
"db:seed": "knex seed:run",
"db:reset": "npm run db:migrate:undo:all && npm run db:migrate && npm run db:seed",
// Git hooks integration
"prepare": "husky install",
"precommit": "lint-staged"
}
}
Useful Dev Dependencies
# Development tooling (devDependencies only):
npm install -D nodemon # Auto-restart on file changes
npm install -D concurrently # Run multiple scripts in parallel properly
npm install -D cross-env # Cross-platform env vars
npm install -D husky # Git hooks
npm install -D lint-staged # Run linters on staged files
npm install -D prettier # Code formatter
npm install -D eslint # Code linter
npm install -D jest # Testing framework
npm install -D @types/node # TypeScript types for Node.js
npm install -D ts-node # Run TypeScript directly
npm install -D rimraf # Cross-platform rm -rf
npm install -D cpx # Cross-platform copy
npm install -D dotenv # Load .env files
Lifecycle Scripts (Special npm Hooks)
{
"scripts": {
// These run automatically at specific times:
"prepare": "husky install",
// Runs BEFORE npm install (and after)
// Good for: installing git hooks, building native deps
"prepublishOnly": "npm run build && npm run test",
// Runs before npm publish
// CRITICAL: ensures you publish built+tested code
"postinstall": "node setup.js || exit 0",
// Runs after npm install
// Good for: setup scripts, dependency checks
// Always use || exit 0 so it does not break installs!
"preversion": "npm run test",
"version": "git add -A && git commit -m 'chore: release v%s'",
"postversion": "git push && git push --tags",
// Runs during npm version (bump patch/minor/major)
"pack": "npm pack --dry-run 2>&1 | head -20",
// Preview what would be published without actually publishing
}
}
Workspaces (Monorepo Management)
// Root package.json
{
"name": "my-monorepo",
"private": true,
"workspaces": [
"packages/*",
"apps/*"
],
"scripts": {
"dev": "concurrently 'npm run dev -w apps/web' 'npm run dev -w api'",
"build": "npm run build --workspaces-if-present",
"test": "npm test --workspaces-if-present",
"lint": "eslint 'packages/*/src' 'apps/*/src'"
}
}
// Benefits:
// - Single node_modules folder (hoisted dependencies)
// - npm install from root installs everything
// - Cross-package references work naturally
// - Commands can run across all or specific workspaces: -w <name>
What is your favorite npm script trick? What is in your package.json that you cannot live without?
Follow @armorbreak for more practical developer guides.
Top comments (0)