What's the Best Way to Do Images in Next.js?
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.
Recommended Setup
Here's the modern approach for list pages with consistent aspect ratios:
1. Install and Configure @sanity/image-url
npm install @sanity/image-urlCreate 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 tablet33vw= 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?
- Native Sanity integration: @sanity/image-url automatically handles hotspot/crop data
- CDN optimization: Leverages Sanity's globally-distributed image CDN
- Next.js benefits: Gets automatic lazy loading, blur placeholders, and responsive images
- Consistent aspect ratios: Using
.width()and.height()with.fit('crop')ensures uniform sizing - Proper browser hints: The
sizesattribute 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.
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.