What's the Best Way to Do Images in Next.js?

11 replies
Last updated: May 6, 2021
what is the “best” way right now to do images in Next.js that supports hotspots, cropping etc? Particularly interested in a list page with images that are all the same size/proportion and deliver all the right browser layout hints. Any examples?
AI Update

For Next.js images with hotspot and cropping support, the best current approach is using @sanity/image-url with Next.js's next/image component. This combination gives you full control over Sanity's hotspot/crop features while delivering optimized images with proper browser hints.

Here's the modern approach for list pages with consistent aspect ratios:

1. Install and Configure @sanity/image-url

npm install @sanity/image-url

Create a reusable URL builder:

// lib/sanityImageUrl.ts
import { createImageUrlBuilder, type SanityImageSource } from '@sanity/image-url'
import { client } from './sanity/client'

const builder = createImageUrlBuilder(client)

export function urlFor(source: SanityImageSource) {
  return builder.image(source)
}

2. List Page Component with Consistent Sizing

For a grid/list where all images should be the same size and aspect ratio:

import Image from 'next/image'
import { urlFor } from '@/lib/sanityImageUrl'

export function ImageGrid({ items }) {
  return (
    <div className="grid grid-cols-3 gap-4">
      {items.map((item) => (
        <div key={item._id} className="relative aspect-square">
          <Image
            src={urlFor(item.image)
              .width(600)
              .height(600)
              .fit('crop')  // Ensures consistent aspect ratio
              .url()}
            alt={item.image.alt || ''}
            fill
            sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
            className="object-cover"
          />
        </div>
      ))}
    </div>
  }
}

Key Points for List Pages

The sizes attribute is crucial for proper browser hints. It tells the browser which image size to download based on viewport:

  • (max-width: 768px) 100vw = full width on mobile
  • (max-width: 1200px) 50vw = half width on tablet
  • 33vw = one-third width on desktop (for 3-column grid)

Hotspot preservation: The @sanity/image-url builder automatically respects hotspot and crop settings from your Sanity Studio. When you use .fit('crop'), it will intelligently crop around the hotspot area.

Enable Hotspot in Your Schema

{
  name: 'image',
  type: 'image',
  options: {
    hotspot: true  // Enables the hotspot/crop UI in Studio
  }
}

Alternative: Responsive Srcset for Different Sizes

For more advanced optimization with multiple breakpoints:

<Image
  src={urlFor(image).width(800).height(800).url()}
  srcSet={[
    `${urlFor(image).width(400).height(400).url()} 400w`,
    `${urlFor(image).width(800).height(800).url()} 800w`,
    `${urlFor(image).width(1200).height(1200).url()} 1200w`,
  ].join(', ')}
  sizes="(max-width: 600px) 400px, (max-width: 1200px) 800px, 1200px"
  alt={image.alt || ''}
/>

Why This Approach?

  1. Native Sanity integration: @sanity/image-url automatically handles hotspot/crop data
  2. CDN optimization: Leverages Sanity's globally-distributed image CDN
  3. Next.js benefits: Gets automatic lazy loading, blur placeholders, and responsive images
  4. Consistent aspect ratios: Using .width() and .height() with .fit('crop') ensures uniform sizing
  5. Proper browser hints: The sizes attribute enables efficient image selection

The combination of Sanity's image pipeline with Next.js's Image component gives you the best of both worlds - smart cropping that respects editorial decisions plus modern web performance optimizations.

I also don’t quite understand how to handle responsive images, where they are different sizes etc for different devices
user M
I actually roll my own photo component to handle images and account for hotspots/cropping/etc. from Sanity
curious why this general topic seems not well established.. did you also jsut not find anything that checked all the boxes of “give me an image that fits correctly in this hole and respects the crop I set”?
Yea exactly, nothing really checked all the boxes, and I wanted full control over the image experience
is hull.dev powered by this? Looks really nice, I might have to borrow this 😬
It is! 😊
damn, I’m going to be spending lots of time in this repo. Wish I wasn’t migrating an existing site
Good luck!
huh interesting. I suppose it’s mostly agnostic to the framework in use. I’ll see how this goes. I actually use very few image types/styles so I don’t need a hugely comprehensive solution

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?