@netlify/images: upgrade Sharp to avoid automatic source builds with global libvips
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 26
- Forks
- 21
- Avg merge
- 22h 38m
- Merged PRs (30d)
- 13
Description
What happened
I installed a fresh Omarchy Quattro system and, naturally, one of the first things I tried as a Netlify employee was installing the Netlify CLI.
The documented global installation failed:
mise use -g node@24
npm install -g netlify-cli
The relevant output was:
sharp: Attempting to build from source via node-gyp
sharp: Please add node-addon-api to your dependencies
This was on Linux x64 with Node 24.19.0 and netlify-cli 27.1.1.
Why it fails
Omarchy intentionally installs the system libvips package for its image picker. During the Netlify CLI installation, Sharp 0.34.5 detects that global copy of libvips and automatically switches from its packaged binary to a source build. That build then fails because its build-time dependencies are not present in the published Netlify CLI dependency tree.
The current dependency chain is:
netlify-cli@27.1.1
└─ @netlify/images@1.3.12 (^1.3.11)
└─ ipx@3.1.1 (^3.1.1)
└─ sharp@0.34.5 (^0.34.3)
The workaround confirms that global-libvips detection is the trigger:
SHARP_IGNORE_GLOBAL_LIBVIPS=1 npm install -g netlify-cli
With that one-command override, the installation succeeds:
netlify-cli/27.1.1 linux-x64 node-v24.19.0
This is not specific to Omarchy. Any supported system with a compatible global libvips installation can take the same Sharp 0.34 source-build path. There is also an upstream Sharp report reproducing the behavior on macOS with Homebrew libvips.
Why this should not be fixed globally in Omarchy
I first proposed setting SHARP_IGNORE_GLOBAL_LIBVIPS=1 in Omarchy's default environment. The review of that change uncovered why it is the wrong system-wide policy:
- It changes Sharp behavior for every Node project on the machine, not just the Netlify CLI installation.
- It prevents users from intentionally using the system libvips. Sharp checks
SHARP_IGNORE_GLOBAL_LIBVIPSbeforeSHARP_FORCE_GLOBAL_LIBVIPS, so a command-scoped force override cannot undo a globally exported ignore value. - Omarchy has a legitimate reason to install libvips, and the presence of that system library should not make an unrelated CLI fail to install.
The durable fix is to move the Netlify dependency tree off Sharp 0.34's automatic source-build behavior.
Proposed path
Sharp 0.35 removed the install script and made source compilation opt-in. IPX 4.0.0-beta.1 already depends on sharp@^0.35.3, but it is ESM-only and includes breaking server API changes. @netlify/images currently uses IPX 3 server APIs (createIPX, createIPXWebServer, ipxFSStorage, and ipxHttpStorage), so this should be treated as a tested dependency migration rather than a blind version bump.
I think the work should be:
- Test IPX 3.1.1 and the
@netlify/imagessuite with Sharp 0.35.3 substituted for Sharp 0.34.5. - If they are compatible, contribute or request an IPX 3.x patch release that updates Sharp. Since
@netlify/imagesalready acceptsipx@^3.1.1, this is the smallest path and avoids the IPX 4 API migration. - If Sharp 0.35 cannot be backported to IPX 3, migrate
@netlify/imagesto IPX 4, adapt the changed server APIs, and account for its Node engine requirement (^20.16.0 || >=22.3.0). - Publish the updated
@netlify/images, update/release the Netlify CLI, and test the final package on a clean machine with system libvips installed and noSHARP_*environment variables.
Acceptance criteria
npm install -g netlify-clisucceeds on a clean Omarchy Quattro installation without settingSHARP_IGNORE_GLOBAL_LIBVIPS.- The same installation succeeds on another supported Linux or macOS environment with a compatible global libvips installation.
netlify --versionruns after installation.- The
@netlify/imagestest suite passes, including local image transformation and HTTP-backed image behavior. - A Netlify CLI smoke test confirms the image functionality that consumes
@netlify/imagesstill works.
Related context
- Omarchy investigation and proposed global workaround: https://github.com/basecamp/omarchy/pull/6984
- Omarchy's intentional libvips dependency: https://github.com/basecamp/omarchy/pull/6686
- Sharp report for the same automatic source-build failure: https://github.com/lovell/sharp/issues/4498
- Sharp 0.35 change making source builds opt-in: https://github.com/lovell/sharp/blob/v0.35.0/docs/src/content/docs/changelog/v0.35.0.md
- IPX 4 beta migration notes: https://github.com/unjs/ipx/releases/tag/v4.0.0-beta.1
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in the @netlify/images dependency manifest and its IPX integration, focusing on createIPX, createIPXWebServer, ipxFSStorage, and ipxHttpStorage. Run the @netlify/images test suite with Sharp 0.35.3 substituted, then verify image transformation, HTTP-backed behavior, Netlify CLI installation, and a CLI image smoke test on a system with global libvips.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- node.js, typescript
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100