TypeScript

Fix Node Sass could not find a binding for your environment

Read the two environment lines in the error, rebuild the binding for the Node that actually runs your build, and know when the only real fix is moving to Dart Sass.

Mahdi Ben RhoumaMahdi Ben Rhouma
8 min read

TL;DR#

node-sass is a native module. npm install downloads one compiled binding.node for the exact Node version and OS that ran the install. When a different Node or OS later runs the build, that file is missing and node-sass stops. If the Node running your build is one node-sass supports, run npm rebuild node-sass with that same Node. node-sass is deprecated and stops at Node 20, so on any newer Node the real fix is to replace it with the sass package (Dart Sass).

The question on Stack Overflow shows the classic form. The terminal says node -v is v6.2.2, yet the error talks about "OS X 64-bit with Node 0.10.x". A rebuild changed nothing because it ran under a different Node from the build.

Here is the same error, reproduced on 4 October in Docker. node-sass 9.0.0 was installed on node:16-alpine, then the same node_modules was run on node:20:

text
Error: Missing binding /app/node_modules/node-sass/vendor/linux-x64-115/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/musl 64-bit with Node.js 16.x
 
This usually happens because your environment has changed since running `npm install`.
Run `npm rebuild node-sass` to download the binding for your current environment.

Why the binding goes missing#

The message gives you two environments, and comparing them is the whole diagnosis:

  • "your current environment" is the Node and OS executing node-sass right now: Linux, glibc, Node 20 in the example above.
  • "Found bindings for" lists what is actually in node_modules/node-sass/vendor/: here, only a binding compiled for Alpine (musl) and Node 16.

Each binding sits in a folder named after the platform and the Node module ABI. In the reproduction, the folder was linux_musl-x64-93 after the Alpine install, and node-sass then looked for linux-x64-115. The node-sass README has a table of Node versions against their module numbers: 93 is Node 16, 115 is Node 20. A different Node major, or the same major on a different C library, means a different binding.

This is how environments drift apart in practice:

  1. A Node upgrade (nvm, Volta, Homebrew) after npm install, with node_modules kept.
  2. node_modules copied into a Docker image from a host on another OS, or from an Alpine stage into a Debian stage, as in the reproduction.
  3. A tool running its own Node. The second Stack Overflow answer is about exactly this: Visual Studio's Task Runner runs gulp with Node bundled inside the IDE, not the Node on your PATH. The fix there is to move $(PATH) above the bundled tools in Visual Studio's External Web Tools settings.

Case 3 is why "npm rebuild node-sass says the binary is fine" is a common complaint. The rebuild runs under your terminal's Node, which has a working binding. The build runs under another Node, which does not.

Fix#

1. Find out which Node runs the build#

Print the version from inside the failing build, not from a fresh terminal. For example, add this as the first line of the gulp, webpack or build script:

js
console.log(process.version, process.platform, process.arch, process.execPath);

process.execPath shows which Node binary is running. If it points inside an IDE, a global tool or a container you did not expect, fix that first (case 3 above). In Docker, run it with docker run --rm <image> node -p process.version.

2. Check that node-sass supports that Node#

node-sass is deprecated on npm. The registry's deprecated field for its last version reads: "Node Sass is no longer supported. Please use sass or sass-embedded instead." The README's support table stops at Node 20 for node-sass 9.0. On Node 22 the same node_modules fails with a different message:

text
Error: Node Sass does not yet support your current environment: Linux 64-bit with Unsupported runtime (127)
For more information on which environments are supported please see:
https://github.com/sass/node-sass/releases/tag/v9.0.0

No prebuilt binding exists for that Node line. npm rebuild can then only try to compile one from source with node-gyp, on a release that is no longer supported or tested. The README says the maintainers "will not block installations for those that want to support themselves", which is not a fix you want to depend on. If your build Node is newer than node-sass supports, skip to step 4.

3. Rebuild the binding with the Node that runs the build#

bash
npm rebuild node-sass

Run it in the same shell, container or CI job that runs the build. In the reproduction, that single command on node:20 downloaded the missing binding next to the old one, and the same build then compiled:

text
rebuilt dependencies successfully
linux-x64-115
linux_musl-x64-93
.btn {
  color: #0b5fff; }

The npm rebuild documentation describes this command as running the package's install scripts again. For node-sass those are scripts/install.js, which downloads a prebuilt binding, and scripts/build.js, which compiles one with node-gyp when no binding is present. If no prebuilt binary exists for your platform, that compile step needs Python and a C++ toolchain. On macOS it fails with gyp: No Xcode or CLT version detected when the Command Line Tools are missing.

In Docker, stop the drift instead of patching it. Do not copy the host's node_modules into the image. List it in .dockerignore (see Docker's build context documentation) and install inside the image, so the binding always matches the image's Node:

dockerfile
FROM node:20-bookworm-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
text
node_modules

The second block is the whole .dockerignore.

4. Replace node-sass with sass#

This is the fix that lasts. The node-sass README opens with: "Node Sass has reached end of life. It will receive no more releases, even for security fixes." The repository is archived. The Sass team's end-of-life announcement points users to Dart Sass, published on npm as sass. It is pure JavaScript, so it has no binding to lose.

bash
npm uninstall node-sass
npm install --save-dev sass

If your build calls node-sass directly, change only the require. The old renderSync call still works:

js
const sass = require('sass');
const out = sass.renderSync({ file: 'style.scss' });
console.log(out.css.toString());

On node:22, this compiled and printed a warning that the old API is on its way out:

text
DEPRECATION WARNING [legacy-js-api]: The legacy JS API is deprecated and will be removed in Dart Sass 2.0.0.

Then move to the new API, documented on the legacy JS API page:

js
const sass = require('sass');
const out = sass.compile('style.scss');
console.log(out.css);

Most setups never call node-sass themselves: sass-loader and Next.js load whichever Sass package is installed, so removing node-sass and adding sass is the whole change there. Vite never used node-sass at all; it asks for sass or sass-embedded.

Verify the fix#

Run the real build with the Node from step 1, and check that nothing still pulls in node-sass:

bash
npm ls node-sass
npm run build

npm ls node-sass should print (empty) after step 4. If it still lists a parent package, that package depends on node-sass itself and needs its own upgrade. After step 3, the vendor folder should contain a binding named for your platform and Node module number, like linux-x64-115 in the reproduction.

One email a month — the latest explained errors

What the site published that month — mostly Next.js, Supabase and Node errors, explained. You confirm by email; unsubscribe any time in one click.

What changes when Dart Sass compiles your styles#

Dart Sass is stricter and newer than LibSass, so the first build after the switch can be noisy without being broken. In the reproduction, the same stylesheet that node-sass compiled silently produced two more warnings. One said that global functions such as darken() are deprecated (see the color functions page), and the other said they will be removed in Dart Sass 3.0.0. The output colour was also written in a different notation, a percentage rgb() where node-sass printed hex. The colour itself is the same. Treat the warnings as a to-do list with links, not as a failure.

Check the engine range as well. The installed sass declares "engines":{"node":">=20.19.0"} in its package.json, so on an older Node, upgrade Node first. Do not reach for node-sass again. One more surprise from the reproduction: require('sass/package.json') fails with "Package subpath './package.json' is not defined by exports", because sass ships an exports map. The package subpath exports fix explains that error. If your Docker build then fails on a missing compiler binary, such as tsc from a devDependency, see tsc not found in Docker.

A binding error is node-sass telling you that your environment moved. On a supported Node, one rebuild under the right Node puts it back. Past Node 20, the environment has moved beyond what node-sass will ever support, and Dart Sass is the package to install.

Further reading: Fix tsc is not recognized: run the local compiler. Also see Fix tar EPERM: operation not permitted, futime.

Frequently Asked Questions

|

Have more questions? Contact us

Still stuck? Paste your error.

Paste the error message or stack trace — we check it against every fix and tool on the site.

Matching happens in your browser. When you search, a cleaned error signature is sent so we can spot errors we do not cover yet — never the raw text, your IP address or your e-mail. Do not paste passwords or keys. Details

Written by

Mahdi Ben Rhouma
Mahdi Ben Rhouma

Full-Stack Dev — Next.js & Supabase

Solo developer building SaaS products with Next.js and Supabase. Writing about production patterns the official docs skip.

Remote