netlify / netlify/primitives

@netlify/images: upgrade Sharp to avoid automatic source builds with global libvips

Open
#748 1 comment 0 reactions 0 assignees View on GitHub

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_LIBVIPS before SHARP_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:

  1. Test IPX 3.1.1 and the @netlify/images suite with Sharp 0.35.3 substituted for Sharp 0.34.5.
  2. If they are compatible, contribute or request an IPX 3.x patch release that updates Sharp. Since @netlify/images already accepts ipx@^3.1.1, this is the smallest path and avoids the IPX 4 API migration.
  3. If Sharp 0.35 cannot be backported to IPX 3, migrate @netlify/images to IPX 4, adapt the changed server APIs, and account for its Node engine requirement (^20.16.0 || >=22.3.0).
  4. Publish the updated @netlify/images, update/release the Netlify CLI, and test the final package on a clean machine with system libvips installed and no SHARP_* environment variables.

Acceptance criteria

  • npm install -g netlify-cli succeeds on a clean Omarchy Quattro installation without setting SHARP_IGNORE_GLOBAL_LIBVIPS.
  • The same installation succeeds on another supported Linux or macOS environment with a compatible global libvips installation.
  • netlify --version runs after installation.
  • The @netlify/images test suite passes, including local image transformation and HTTP-backed image behavior.
  • A Netlify CLI smoke test confirms the image functionality that consumes @netlify/images still works.

Related context

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.