/commands/nodejs/node-run-package-json-script
node --run build: run a package.json script without npm
- tool
- Node.js
- versions
- Node.js 22+
- os
- any
node --run build runs the build script from the nearest package.json, the same command npm run build would run, but without starting npm. It was added in Node.js 22.0.0. It is meant for quick local scripts: it does not run pre/post scripts and sets fewer environment variables than npm.
Run a script
cat > package.json <<'EOF'
{
"name": "app",
"scripts": {
"prehello": "echo this pre script is skipped",
"hello": "node -e \"console.log('hello from', process.env.NODE_RUN_SCRIPT_NAME)\"",
"args": "node print-args.js"
}
}
EOF
echo 'console.log(process.argv.slice(2));' > print-args.js
node --run hello
node --run args -- --watch srcOutput
hello from hello [ '--watch', 'src' ]
Only hello runs; the prehello script that npm run hello would run first is ignored. Instead of npm's variables, node --run sets NODE_RUN_SCRIPT_NAME (the script name) and NODE_RUN_PACKAGE_JSON_PATH (the package.json it read), and arguments after -- are appended to the command.
A script that does not exist
echo '{ "name": "app", "scripts": { "build": "echo building" } }' > package.json
node --run biuld 2>&1 | grep -v "^$" | sed 's/ for .*package.json$/ for package.json/'
exit "${PIPESTATUS[0]}"Output · exit 1
Missing script: "biuld" for package.json Available scripts are: build: echo building
Node.js prints the missing name and the available scripts and exits with code 1, much like npm's Missing script error. node --run with no name is an error (--run requires an argument); use npm run to list scripts.
node --run vs npm run
| Behaviour | node --run | npm run |
|---|---|---|
| Starts npm | No | Yes |
| pre and post scripts | Not run | Run (prebuild, postbuild) |
| node_modules/.bin on PATH | Yes, from the current folder and its parents | Yes |
| Environment | NODE_RUN_SCRIPT_NAME and NODE_RUN_PACKAGE_JSON_PATH only | npm_lifecycle_event, npm_package_* and npm_config_* variables |
| Workspaces (--workspace) | Not supported | Supported |
| Arguments after -- | Appended to the command | Appended to the command |
| Shell on Windows | cmd.exe | cmd.exe (script-shell can change it) |
The script is run by the system shell: /bin/sh on Linux and macOS, cmd.exe on Windows. A script such as echo $HOME therefore prints the literal text on Windows with both tools. Write cross-platform scripts as node -e or small .js files, as in the example above.
Pitfalls
- Scripts that call
npm run otherstill start npm, so the speed gain is lost for chained scripts. - Tools that read
npm_lifecycle_event,npm_package_*ornpm_config_*from the environment see nothing undernode --run. node --runlooks forpackage.jsonin the current folder and then in its parents, so it can run a script from an enclosing project when the folder has none.
How to confirm it worked
node --run exits with the script's exit code, so node --run test; echo $? shows whether the script passed. Check that your Node.js has the flag with node --help | grep -- --run; on Node.js 20 and older it fails with bad option: --run.
FAQ
Is node --run faster than npm run?
It starts faster because it does not load npm. The Node.js documentation describes it as a lighter alternative that deliberately skips features of npm run, such as pre and post scripts, to keep startup cheap.
Does node --run run prebuild and postbuild?
No. Only the named script runs. If your project relies on pre or post scripts, keep using npm run, or call the steps explicitly in one script.
How do I pass arguments with node --run?
Put them after --, for example node --run test -- --watch. Everything after the double dash is appended to the script command, as with npm run.