Two different Node "version" problems get confused for each other. One is a hard crash — the Node you're running is older than the syntax your code uses, so it can't even parse the file. The other is just a warning from npm that a package would prefer a different Node. This guide reads both and points you at the one dial that fixes them: the version picker in Settings.
| At a glance | |
|---|---|
| SyntaxError at startup | Running Node is too old for your code's syntax — a real crash |
npm warn EBADENGINE |
A package prefers another Node version — only a warning |
| The fix | Switch the Node version in Settings (any plan) |
The hard one: SyntaxError
Modern JavaScript features are tied to Node versions. Run code that uses a feature your Node doesn't understand, and it fails before your code runs — the parser rejects the file. On an older Node, a class static block (a Node 16.11+ feature) crashes like this:
/home/container/index.js:2
static {
^
SyntaxError: Unexpected token '{'
at wrapSafe (internal/modules/cjs/loader.js:1029:16)
The tell is the shape: a SyntaxError pointing at a modern construct (?., ??, static blocks, top-level await, #private fields), thrown at load time. It isn't a typo — it's a version gap. The same happens with a dependency: if a package ships newer syntax than your Node, its file is the one in the stack trace.
🎯 Good to know: The default here is Node 20, which is thoroughly modern — so this usually bites only after you deliberately switch to an old version, or pull in a package that expects a newer one than you're on.
The soft one: EBADENGINE
A package can declare which Node it supports in its engines field. When yours doesn't match, npm prints a warning during install:
npm warn EBADENGINE Unsupported engine {
npm warn EBADENGINE package: '[email protected]',
npm warn EBADENGINE required: { node: '>=22.0.0' },
npm warn EBADENGINE current: { node: 'v20.20.2', npm: '11.18.0' }
npm warn EBADENGINE }
Read the required vs current lines — they name the mismatch exactly. But notice what happens next: the install finishes anyway. EBADENGINE is advisory. If your app then runs fine, you can ignore it. It only becomes a real problem if that package actually uses syntax or APIs your Node lacks — at which point you get a crash (often the SyntaxError above) and the version bump is warranted.
| You see | Severity | What to do |
|---|---|---|
SyntaxError on a modern feature |
Crash — app won't run | Move to a newer Node in Settings |
npm warn EBADENGINE then a clean start |
Warning only | Ignore, or bump to satisfy it |
npm warn EBADENGINE then a crash |
The warning came true | Bump to the required version |
The fix: the version picker
Node version switching is on the Settings page (the runtime/Docker-image dropdown), on any plan — no premium needed. Versions 12 through 25 are selectable; the default is 20.
- Read the version your code or package needs (the
requiredline, or the release that introduced the syntax). - Open Settings, pick that Node version.
- Restart. The next start runs on the new version — and re-runs
npm install, so native modules rebuild for it too.
⚠️ Heads up: Going older to satisfy one stubborn dependency can break others that needed the newer Node. Prefer moving up to the newest version everything supports, not down.
Beyond version selection, everything about Node itself is standard — the release notes at nodejs.org list exactly which feature landed in which version.