How to Install esbuild in CI Without Platform Binary Errors
esbuild ships a prebuilt Go binary per platform through optional dependencies. CI breaks when the installed binary does not match the runner OS or arch.
esbuild has no node-gyp build - it downloads a platform-specific binary (e.g. @esbuild/linux-x64) as an optional dependency. The classic CI failure is a lockfile or node_modules created on one platform being used on another, so the wrong binary is present.
Why it fails in CI
- You committed node_modules or a lockfile built on macOS/Windows, then ran on Linux - the optional binary is for the wrong platform.
- Optional dependencies were omitted (
npm ci --omit=optional), so no esbuild binary installed at all. - Alpine/musl needs
@esbuild/linux-x64-musl, not the glibc variant.
Install it reliably
Install fresh on the target platform and keep optional dependencies enabled so esbuild resolves the correct binary. Never copy node_modules across OS or arch.
# clean install on the actual runner platform
npm ci
# do NOT omit optional deps - that drops the platform binary
# (avoid: npm ci --omit=optional)
# on Alpine the musl variant resolves automatically with a clean install
# (esbuild detects musl at install time)Cache & speed
Cache ~/.npm keyed on the lockfile and runner OS so the binary download is reused. If you cache node_modules, include runner.os and arch in the key so a different platform leg never reuses the wrong binary.
- uses: actions/cache@v4
with:
path: ~/.npm
key: npm-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}Common errors
Host version "0.x" does not match binary version "0.y"→ cross-platform node_modules; reinstall fresh.Cannot find module '@esbuild/linux-x64'→ optional deps were omitted; reinstall with optional deps enabled.- On Alpine
Error: Cannot find module ...musl→ use a clean install so the musl binary resolves.
Key takeaways
- esbuild downloads a platform binary via optional dependencies - keep them enabled.
- Never copy node_modules across OS/arch; install fresh on the runner.
- Key any node_modules cache on runner.os + arch to avoid binary mismatch.