Next.js 16.3.4 / 15.5.25 Re-enable AVIF Optimization
On August 31, 2026 Vercel shipped 16.3.4 and 15.5.25, which undo the most
disruptive part of the previous week's security release: AVIF image optimization
works again. The two lines get there by different routes, and the difference
matters. 15.5.25 checks the libheif version bundled with sharp at runtime and
only decodes AVIF if that version is patched. 16.3.4 does not check anything —
it relies entirely on the sharp version your install resolves.
If you upgraded to 16.3.3 and moved on, the practical consequence is this: on 16.3.4 the safety of AVIF decoding is a property of your lockfile, not of Next.js.
What was broken and why
The August 25 release fixed
a Critical heap overflow in libheif
reachable through the Image Optimization API. Because the patched libheif had
not propagated down the sharp dependency chain yet, Vercel's fix took the blunt
option: AVIF joined BYPASS_TYPES alongside SVG and ICO, VipsForeignLoadHeif
was removed from sharp's unblocked operations, and AVIF fell out of
VALID_BLUR_EXT. AVIF source images were passed through unoptimized and static
AVIF imports lost their blur placeholders.
That trade was worth making at the time. It was never meant to be permanent.
16.3.4: a revert plus a dependency floor
PR #97949 is two commits. The
first reverts the disable wholesale — BYPASS_TYPES goes back to
[SVG, ICO, ICNS, BMP, JXL, HEIC], VipsForeignLoadHeif returns to the unblock
list, and 'avif' is restored to the valid blur extensions in blur.ts,
get-img-props.ts and image.tsx. Roughly 137 lines of workaround come out.
The second commit bumps sharp in packages/next/package.json from ^0.35.3
to ^0.35.4. That is the entire safety mechanism. The libheif fix ships inside
sharp's prebuilt libvips binaries rather than in Next.js code, so the version
floor on sharp is what separates a patched decoder from an unpatched one.
Read the shipped image-optimizer.ts on the v16.3.4 tag and there is no
version guard: AVIF is optimized whenever sharp loads.
sharpis an optional dependency ofnext. A floor in Next.js'spackage.jsonconstrains what a fresh install pulls. It does not upgrade asharpyou installed yourself, pinned in your own dependencies, or baked into a container image.
15.5.25: an actual runtime check
The 15.5 line could not take the same shortcut.
PR #97954 explains why: "Since
15.x supports a Node.js version not supported by a secure sharp version, we have
to conditionally block AVIF optimization based on the used libheif version."
Its sharp range is ^0.34.3 || ^0.35.4, which deliberately admits an older
major.
So 15.5.25 asks the library at startup. image-optimizer.ts gains an
isAvifDecodeSafe() helper that parses sharp.versions.heif and returns true
only for libheif 1.23.2 or newer — the version that carries the upstream
fix:
if (isAvifDecodeSafe(heifVersion)) {
sharp.unblock({ operation: ['VipsForeignLoadHeif'] })
}
Run 15.5.25 against an old sharp and AVIF stays bypassed. Run 16.3.4 against the same old sharp and it does not.
What to do
Upgrade, then verify the resolution rather than assuming it:
npm install next@16.3.4 # or next@15.5.25
npm ls sharp
node -e "console.log(require('sharp').versions)"
The second command tells you which sharp actually won; the third prints the
bundled library versions, including heif. You want heif at 1.23.2 or above.
If it is lower, either upgrade sharp or keep AVIF out of your optimizer's
reach — images.formats controls output, but the decode path is entered by any
AVIF source, including remote URLs matched by images.remotePatterns and user
uploads.
Two follow-ups. If you set your own blurDataURL as a workaround for statically
imported AVIF images losing their placeholder in 16.3.3, that workaround is now
redundant but harmless. And if you run a custom Node.js image with a
system-level sharp, this is the exact scenario the 16.3.x approach does not
cover; pin sharp explicitly at >=0.35.4 in your own package.json so the
constraint is yours rather than inherited.
16.3.4 also backports three unrelated fixes: infinite recursion in testmode
passthrough fetch (#97691), build errors when aliasing TypeScript to
@typescript/typescript6 (#97997), and unset crossOrigin attributes in
Turbopack manifests (#97930). It explicitly does not include pending canary
work — 16.4 is still in canary.
Primary sources: the v16.3.4 and v15.5.25 release tags, and PRs #97949 and #97954.
Not sure what sharp your production image is really resolving, or whether your
image pipeline is still bypassing AVIF? Get in touch — auditing and
upgrading Next.js deployments is what we do.