The problem: After upgrading the server's PHP version, an unrelated npm run build step starts failing with a Node Sass binding error, even though nothing in the JS toolchain was touched.
Environment: Laravel 11, node-sass (legacy), Node 20, PHP 8.3 (upgraded from 8.1), Forge/Ubuntu server
The Error
Error: Missing binding /var/www/app/node_modules/node-sass/vendor/linux-x64-108/binding.node
Node Sass could not find a binding for your current environment:
Linux 64-bit with Node.js 20.x
Found bindings for the following environments:
- Linux 64-bit with Node.js 16.x
Why It Happens
This one is a red herring — it looks PHP-related because it started right after a PHP upgrade, but it's actually a coincidental Node.js version bump. Most server upgrade scripts (and Forge's PHP version switcher especially) also touch the system's Node version or trigger a fresh nvm/apt install alongside the PHP change, since both are often bundled in the same provisioning step.
node-sass ships prebuilt native binary bindings compiled for a specific Node ABI version — it does not compile from source automatically like Dart Sass does. When Node jumps from v16 to v20 as a side effect of the server upgrade, the old prebuilt binding for v16 no longer matches, and node-sass has no fallback; it just fails outright instead of degrading gracefully.
This is also a strong signal to migrate off node-sass entirely — it's been deprecated in favor of Dart Sass (the sass npm package) for years, and this exact binding-mismatch failure is one of the most common reasons legacy Laravel projects finally make the switch.
The Fix
The most durable fix is replacing node-sass with Dart Sass, which has no native binding to break:
npm uninstall node-sass
npm install -D sass
Update any build config or import referencing node-sass specifically (rare in modern Vite setups, but common in older Laravel Mix configs):
mix.js('resources/js/app.js', 'public/js')
.sass('resources/sass/app.scss', 'public/css', {}, { implementation: require('sass') });
If you can't migrate off node-sass immediately (large legacy codebase, time pressure), pin the Node version explicitly instead, so it always matches a version node-sass has a prebuilt binding for:
16
nvm install
nvm use
npm run build
Step-by-Step
- Run
node -von the server to confirm the actual Node version changed alongside the PHP upgrade. - Decide between migrating to Dart Sass (recommended, permanent) or pinning Node back to a compatible version (quick, temporary).
- For migration:
npm uninstall node-sass && npm install -D sass, then update any explicitimplementationreferences in Mix/Vite config. - For pinning: add an
.nvmrcfile and runnvm install && nvm usebefore every deploy going forward. - Delete
node_modulesand reinstall clean to avoid stale binding cache issues:rm -rf node_modules package-lock.json && npm install. - Run
npm run buildagain and confirm it completes without the binding error.
Edge case: If your CI/CD pipeline (GitHub Actions, Forge deploy script) has its own separate Node version pinned independently from the server's system Node, fixing the server locally won't fix the deploy pipeline — you'll need to update the Node version in your CI config file too, or the same binding error will resurface on the next automated deploy even after a successful local fix.
Still hitting build errors after switching to Dart Sass?