npm Scripts: Unlocking the Full Power of package.json
Most developers only use npm start and npm test. Here's what you're missing.
The Basics
{
"scripts": {
"start": "node server.js",
"test": "jest",
"build": "tsc"
}
}
Run with: npm run start or npm start (for start/test only)
Key insight: npm scripts automatically add node_modules/.bin to your PATH. So you can run locally-installed CLI tools directly!
Common Useful Scripts
{
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js",
"build": "tsc && vite build",
"test": "jest --coverage",
"test:watch": "jest --watch",
"lint": 'eslint "src/**/*.{ts,js}"',
"lint:fix": 'eslint "src/**/*.{ts,js}" --fix',
"format": "prettier --write \"src/**/*.{ts,js,json,md}\"",
"clean": "rm -rf dist build .turbo",
"typecheck": "tsc --noEmit",
"prepare": "husky install"
}
}
Pre/Post Hooks
{
"scripts": {
"prebuild": "npm run lint && npm run typecheck",
"build": "tsc",
"postbuild": "npm run clean:old && echo 'Build complete!'",
"pretest": "npm run db:migrate:latest",
"test": "jest",
"posttest": "npx codecov"
}
}
When you run npm run build, it automatically runs:
-
prebuild(lint + typecheck) -
build(compile) -
postbuild(cleanup)
Same for npm test: pretest → test → posttest
Variables & Arguments
# Pass arguments to scripts
npm run test -- --grep "auth" # -- passes everything after to the script
npm run dev -- --port 8080 # Pass port to nodemon
npm run build -- --watch # Pass watch flag to tsc
# Use variables in scripts
# package.json:
{
"scripts": {
"serve": "serve -l $PORT dist/"
}
}
# Terminal:
PORT=3000 npm run serve
Chaining Commands
{
"scripts": {
// Sequential (run one after another, stop on failure)
"setup": "npm install && npm run build && npm run migrate",
// Parallel (run all at once)
"validate": "npm run lint & npm run typecheck & wait",
// Regardless of previous result
"cleanup": "npm run clean; rm -rf logs/*",
// Conditional
"deploy": "npm run test && npm run build && npm run push:prod"
}
}
Cross-Platform Scripts
// ❌ Won't work on Windows
"clean": "rm -rf dist/"
// ✅ Use cross-env for env vars
// npm install -D cross-env
"build": "cross-env NODE_ENV=production webpack"
// ✅ Use rimraf for file operations
// npm install -D rimraf
"clean": "rimraf dist/"
// ✅ Use npm-run-all for parallel execution
// npm install -D npm-run-all
"validate": "npm-run-all lint typecheck test"
// ✅ Use shx for shell commands (cross-platform)
// npm install -D shx
"copy": "shx cp src/index.html dist/"
Script Organization (Large Projects)
{
"scripts": {
// Development
"dev": "nodemon server.js",
"dev:debug": "node --inspect server.js",
// Building
"build": "tsc",
"build:watch": "tsc --watch",
"build:production": "tsc && vite build",
// Quality
"lint": 'eslint src/',
"lint:fix": 'eslint src/ --fix',
"typecheck": "tsc --noEmit",
"format": "prettier --write src/",
"format:check": "prettier --check src/",
// Testing
"test": "jest",
"test:e2e": "playwright test",
"test:coverage": "jest --coverage",
"test:watch": "jest --watch",
// Database
"db:migrate": "prisma migrate dev",
"db:migrate:prod": "prisma migrate deploy",
"db:seed": "prisma db seed",
"db:studio": "prisma studio",
// Deployment
"deploy": "npm run build && npm run deploy:cf",
"deploy:cf": "wrangler deploy",
"deploy:vercel": "vercel --prod",
// Utility
"clean": "rimraf dist build .cache",
"deps:check": "npm outdated",
"deps:update": "npm update && npm audit fix"
}
}
Pro Tips
1. Script Alias with npx
# Run any npm package without installing globally
npx create-react-app my-app
npx tsc --version # Check TypeScript version
npx prettier . --check # Check formatting
npx http-server ./dist # Quick local server
npx cowsay "Hello!" # Fun stuff too
2. Workspaces (Monorepo Scripts)
// Root package.json
{
"workspaces": ["packages/*"],
"scripts": {
"build": "npm run build --workspaces-if-present",
"test": "npm test --workspaces-if-present",
"dev": "concurrently \"npm run dev:*\""
}
}
3. Lifecycle Scripts (Automatic)
{
"scripts": {
"prepare": "husky", // Runs after npm install
"prepublishOnly": "npm run build && npm test", // Before npm publish
"preinstall": "node check-node-version.js", // Before npm install
"postinstall": "patch-package" // After npm install
}
}
| When | What Runs |
|---|---|
npm install |
preinstall → install → postinstall |
npm publish |
prepublishOnly → prepublish → publish |
npm run xxx |
prexxx → xxx → postxxx |
4. Debug Your Scripts
# See what command actually runs
npm run build --verbose
# Dry run (don't execute)
npm run build --dry-run
# Print each command as it runs
# In script: set -x (bash) or use npm config
npm config set script-shell bash
What's your favorite npm script trick?
Follow @armorbreak for more Node.js content.
Top comments (0)