← Back to blog

Published on Tue Oct 21 2025 21:30:00 GMT+0000 (Coordinated Universal Time) by cresencio

The Error That Won’t Quit

Deployed to Vercel. Build failed. Classic.

MissingSharp: Could not find Sharp. 
Please install Sharp (`sharp`) manually into your project

Sure, Sharp was in my package.json. Sure, it was installing. But pnpm 10.x has this lovely security feature where it ignores build scripts by default. Every. Single. Time.

╭ Warning ──────────────────────────────────────╮
│ Ignored build scripts: esbuild, sharp.       │
│ Run "pnpm approve-builds" to pick which       │
│ dependencies should be allowed to run scripts.│
╰───────────────────────────────────────────────╯

Cool. Very helpful. Except pnpm approve-builds doesn’t work in CI environments like Vercel.

Things I Tried (That Didn’t Work)

1. Created .npmrc

enable-pre-post-scripts=true
ignore-scripts=false

Result: Ignored. pnpm still blocked Sharp’s install scripts.

2. Created .pnpm-approvals.json

{
  "approved": ["esbuild", "sharp"]
}

Result: Also ignored. Apparently this isn’t a real thing.

3. Modified vercel.json with various hacks

  • pnpm install --no-frozen-lockfile - Nope
  • cd node_modules/sharp && npm run install - Nope
  • Switching to npm entirely - Could work but wanted to keep pnpm locally

What Actually Worked

One simple line in vercel.json:

{
  "installCommand": "pnpm install --no-frozen-lockfile && npm rebuild sharp"
}

That’s it. Let pnpm do its thing, then use npm to rebuild Sharp’s native bindings. The npm rebuild command doesn’t care about pnpm’s security theater - it just builds the damn package.

Why This Works

  1. pnpm install --no-frozen-lockfile - Installs all dependencies (Sharp gets downloaded but not built)
  2. npm rebuild sharp - Explicitly rebuilds Sharp with its native bindings, bypassing pnpm’s build script restrictions

Sharp needs native bindings for image processing. Without running its install scripts, those bindings never get compiled. npm’s rebuild command forces the compilation to happen.

The Alternative (If You Don’t Care About Image Optimization)

If you just want the build to pass and don’t need image optimization, you can use Astro’s noop image service:

// astro.config.ts
export default defineConfig({
  image: {
    service: {
      entrypoint: 'astro/assets/services/noop'
    }
  },
  // ... rest of config
});

But who wants unoptimized images? Not me.

Lessons Learned

  1. pnpm 10.x’s build script security is aggressive (maybe too aggressive?)
  2. Vercel doesn’t let you interactively approve builds
  3. npm rebuild <package> is your friend when fighting package manager wars
  4. Sometimes the simple solution is just using both package managers

Now my images are optimized, my builds pass, and I can go back to writing about sports analytics instead of debugging dependency hell.

TL;DR

Add this to vercel.json:

{
  "installCommand": "pnpm install --no-frozen-lockfile && npm rebuild sharp"
}

Move Sharp to dependencies (not devDependencies):

{
  "dependencies": {
    "sharp": "^0.32.6"
  }
}

Commit, push, and watch your Vercel build actually work.

Written by cresencio

← Back to blog