Fixed: npm Run Build Fails With Node Sass Error After PHP Upgrade

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

● ● ●  terminal
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):

webpack.mix.js
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:

.nvmrc
16
nvm install
nvm use
npm run build

Step-by-Step

  1. Run node -v on the server to confirm the actual Node version changed alongside the PHP upgrade.
  2. Decide between migrating to Dart Sass (recommended, permanent) or pinning Node back to a compatible version (quick, temporary).
  3. For migration: npm uninstall node-sass && npm install -D sass, then update any explicit implementation references in Mix/Vite config.
  4. For pinning: add an .nvmrc file and run nvm install && nvm use before every deploy going forward.
  5. Delete node_modules and reinstall clean to avoid stale binding cache issues: rm -rf node_modules package-lock.json && npm install.
  6. Run npm run build again 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?

Advertisement