Custom Next.js image blur placeholders
Next.js Image Optimization is a web framework at its best: Next.js took a huge problem—image loading—that I’d wasted a ton of time making bad solutions to, and made the ideal implementation the default option. The first iteration had serious drawbacks from both API & UX perspectives, but the Vercel team listened, rewrote it, and the newer one is top-tier. It’s perfect vertical integration.
next/image’s blur-up placeholder, controlled by the
blurDataURL prop, is a nice progressive enhancement, and a massive improvement for large header backgrounds. If you’re making a low-traffic site, though, the source image for a lander will leave the cache sometimes, and visitors will be left with either nothing (if the image source is remote) or a super low-res placeholder for several seconds while the image resizes and downloads. I was noticing this on the Dispersions website I made, which hosts images on a separate CDN to keep the Git repo smaller.
next/image author @styfle recently in Indianapolis, he reminded me the
blurDataURL generated when you statically import an image is merely the URL to a super tiny version of the image. In production, that’s an image encoded as a (no surprise here) base64 data URL, e.g.
In development, if you inspect the
StaticImport object itself, the
blurDataURL prop is:
Curious about the discrepancy?
The source code has this comment describing it:
next dev, we don't want to generate blur placeholders with webpack because it can delay starting the dev server. Instead,
next-image-loader.jswill inline a special url to lazily generate the blur placeholder at request time.
That URL is resizing the image to 8px wide, then
next build is transforming it into a data URL. Therefore, if we want a custom blur-up placeholder that’s higher-quality, or for a remote image, we can:
- Get a thumbnail version of our image (say, 12 or 16px wide), either via the
/_next/imageURL or another resizer
- Convert it to base64
- Add the prop manually
I wrote a quick macOS Shortcut to do this: after you install it, right-click an image in Finder, click the shortcut, then paste the prop into your Image tag. The Dispersions site now appears to load far faster, with a decent-fidelity blur-up placeholder appearing immediately in the header instead of several seconds of grey waiting.
If you’re looking to generate these placeholders automatically from a remote image source, while you could roll your own, I recommend @joe-bell’s plaiceholder project instead, which makes this super easy.