Course:Node.js & Express/
Lesson

Every Node.js project ends up with a handful of commands you type over and over: start the server, run tests, build for production. npm scripts let you store those commands in one place so anyone joining your project can hit the ground running with a simple npm start instead of hunting through a README for the right incantation.

Defining and running scripts

Scripts live in the "scripts" field of your package.json. The key is the name you'll call, and the value is the shell command that runs.

json
{
  "scripts": {
    "start": "node src/index.js",
    "dev": "node --watch src/index.js",
    "test": "node --test",
    "build": "echo 'Building...'"
  }
}

To run them:

npm start        # No 'run' needed for start, test, stop, restart
npm test         # Same shortcut
npm run dev      # Custom scripts need 'run'
npm run build
npm has a small list of "built-in" script names, start, test, stop, and restart, that get special treatment and skip the run keyword. Every other name requires npm run.
02

Building a real script setup

A realistic project has more than a start command. Here is what a typical Node.js + TypeScript project looks like:

json
{
  "scripts": {
    "start": "node dist/index.js",
    "dev": "nodemon src/index.js",
    "build": "npm run clean && npm run compile",
    "clean": "rm -rf dist",
    "compile": "tsc",
    "test": "jest",
    "test:watch": "jest --watch",
    "test:coverage": "jest --coverage",
    "lint": "eslint src/",
    "lint:fix": "eslint src/ --fix",
    "format": "prettier --write src/",
    "db:migrate": "prisma migrate dev",
    "db:seed": "node scripts/seed.js"
  }
}

Notice the naming patterns: test:watch and test:coverage group related scripts under a shared prefix separated by a colon. npm does not treat these specially, the colon is just a convention, but it keeps things readable.

03

Pre and post hooks

npm automatically looks for scripts named pre[name] and post[name] and runs them before and after the target script. You do not need to call them yourself.

json
{
  "scripts": {
    "prestart": "npm run build",
    "start": "node dist/index.js",
    "poststart": "echo 'Server is up!'"
  }
}

Running npm start now executes three steps in order:

# 1. prestart runs first
# 2. start runs
# 3. poststart runs last

Some hooks that apply at the package level (not just your custom scripts) are worth knowing:

HookWhen it runs
preinstall / postinstallBefore / after npm install
prepareAfter install and before publish
prepublishOnlyRight before npm publish
versionAfter a version bump
postversionAfter the version commit is made
04

Passing arguments and environment variables

Sometimes you want to tweak a script without making a whole new entry. You can forward extra flags using --:

npm run test -- --verbose
npm run test -- --testPathPattern user.test.js
npm start -- --port 8080

For environment variables, the syntax differs between Unix and Windows. On macOS/Linux you can write:

json
{
  "scripts": {
    "dev": "NODE_ENV=development node src/index.js"
  }
}

On Windows this breaks. The fix is cross-env, which normalises the syntax across platforms:

npm install --save-dev cross-env
json
{
  "scripts": {
    "dev": "cross-env NODE_ENV=development node src/index.js",
    "prod": "cross-env NODE_ENV=production node dist/index.js"
  }
}
Always use cross-env in open-source packages or team projects where developers might be on Windows. It is a tiny dependency that prevents a frustrating class of "it works on my machine" bugs.
05

Running scripts in parallel

By default, when you chain two scripts with &&, the second one only starts after the first finishes. That is fine for builds, but terrible for development where you want an APIWhat is api?A set of rules that lets one program talk to another, usually over the internet, by sending requests and getting responses. server and a frontend watcher running at the same time.

npm-run-all gives you explicit control:

npm install --save-dev npm-run-all
json
{
  "scripts": {
    "start:api": "node api.js",
    "start:web": "node web.js",
    "dev": "npm-run-all --parallel start:api start:web",
    "build": "npm-run-all --sequential clean compile"
  }
}
06

Quick reference

PatternExampleWhat it does
Basic script"dev": "nodemon src/index.js"Runs a command
Chained scripts"build": "npm run clean && tsc"Runs sequentially
Pre/post hook"pretest": "npm run lint"Runs automatically
Pass argumentsnpm run test -- --verboseForwards flags
Env variablecross-env NODE_ENV=productionWorks cross-platform
Parallelnpm-run-all --parallel a bRuns simultaneously
Grouped namestest:unit, test:e2eConvention only (colon)