Skip to content

/commands/nodejs/check-syntax-without-running

node --check file.js: check JavaScript syntax without running it

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash) · v24.20.0updated
tool
Node.js
versions
Node.js 10+
os
any

node --check app.js (short form node -c app.js) parses the file and reports syntax errors without executing it. It prints nothing and exits with code 0 when the syntax is valid, and prints the error with the line number and exits with code 1 when it is not. It is a cheap gate for CI jobs, Git hooks and deployment scripts that must not start a broken file.

Check a valid and a broken file

bash
printf 'const sum = (a, b) => a + b;\nconsole.log(sum(1, 2));\n' > ok.js
printf 'function broken( {\n  return 1;\n}\n' > broken.js
node --check ok.js && echo "ok.js: syntax OK"
node --check broken.js 2>&1 | grep -E "^SyntaxError|broken.js:"
echo "exit code: ${PIPESTATUS[0]}"

Output

ok.js: syntax OK
/tmp/work/broken.js:2
SyntaxError: Unexpected number
exit code: 1

The valid file is parsed but not run, so its console.log never prints. For the broken file Node.js prints the file and line, the offending source line with a caret, then the SyntaxError message, and exits with 1.

What it does and does not catch

ProblemCaught by node --check
Missing bracket, parenthesis or quoteYes
Invalid keyword use (top-level await in CommonJS, return at the top level of an ES module)Yes
import/export in a file marked as CommonJSYes: Cannot use import statement outside a module
Undefined variable or functionNo, it is only a run-time ReferenceError
Missing module in require or importNo, modules are not resolved
TypeScript filesNo: type annotations are reported as syntax errors; use tsc --noEmit

The module type follows the usual rules: a .mjs file, or a .js file under a package.json with "type": "module", is parsed as an ES module, and a .cjs file or a "type": "commonjs" package as CommonJS. A .js file with no type set goes through Node.js syntax detection, so top-level await or import passes there; the same file fails under "type": "commonjs".

Useful variants

CommandWhat it does
node -c app.jsShort form of --check
node --check app.mjsChecks the file as an ES module
find src -name '*.js' -print0 | xargs -0 -n1 node --checkChecks every .js file, one node process each
git diff --cached --name-only -- "*.js" | xargs -n1 node --checkPre-commit hook: only the staged JavaScript files
echo 'let x = 1' | node --checkChecks code read from standard input

Pitfalls

  • node --check checks one file: in node --check a.js b.js only a.js is parsed, and b.js is treated as an argument to the script. Loop over files instead.
  • It does not apply type stripping: node --check app.ts reports the first type annotation as a SyntaxError even on Node.js versions that run node app.ts.
  • A file that passes can still fail when it runs, so keep tests and a linter in the pipeline. Use --check as the fast first step, not as the only one.

How to confirm it worked

Check the exit code: node --check app.js; echo $? prints 0 for valid syntax and 1 for a syntax error. In a shell script, node --check app.js || exit 1 stops the script on the first broken file. The meaning of other exit codes is listed in Node.js exit codes.

FAQ

Does node --check find undefined variables or wrong imports?

No. It only parses the file. A call to a function that does not exist, a misspelt variable or an import of a missing module is valid syntax and passes; only running the code or a linter such as ESLint finds those.

How do I check every file in a folder?

node --check takes one file per run, so loop over them, for example find src -name '*.js' -print0 | xargs -0 -n1 node --check. xargs checks every file and exits with code 123 if any of them failed, which fails a CI step.

Can node --check validate JSON?

Not as a JSON file. Parse it instead with node -e "JSON.parse(require('fs').readFileSync('data.json','utf8'))", which exits non-zero and prints the position of the first error.

Sources