Discussion about scaling product images in Sanity with Next.js for an ecommerce platform, including suggestions for using the next-sanity-image library and enveloping the...
Welcome to Sanity! Image scaling issues with Next.js are pretty common when you're just getting started, so you're definitely not alone here. The good news is that there are some well-established patterns for handling Sanity images with Next.js.
The main thing you're likely running into is that you need to properly respect the hotspot and crop data that Sanity provides when you enable those features in your schema. Here's what you need to know:
Enable Hotspot in Your Schema
First, make sure you've enabled the hotspot feature in your image field definition:
{
name: 'image',
type: 'image',
options: {
hotspot: true
}
}This allows content editors to define a focal point that should remain visible when the image is cropped or resized - super important for product images where you want to keep the main product in view!
Using Images with Next.js
For Next.js projects, I'd recommend using the next-sanity-image package - it's specifically designed to bridge Sanity's image pipeline with the Next.js Image component and handles all the complexity around hotspot, crop, and responsive sizing.
Install it:
npm install next-sanity-imageThen use it like this:
import { createClient } from '@sanity/client';
import Image from 'next/image';
import { useNextSanityImage } from 'next-sanity-image';
const client = createClient({
projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,
dataset: process.env.NEXT_PUBLIC_SANITY_DATASET,
useCdn: true
});
const ProductImage = ({ product }) => {
const imageProps = useNextSanityImage(client, product.image);
return (
<Image
{...imageProps}
style={{ width: '100%', height: 'auto' }}
sizes="(max-width: 800px) 100vw, 800px"
placeholder="blur"
blurDataURL={product.image.asset.metadata.lqip}
/>
);
};Manual Approach with Image URL Builder
If you prefer more control, you can use @sanity/image-url directly:
import imageUrlBuilder from '@sanity/image-url';
const builder = imageUrlBuilder(client);
function urlFor(source) {
return builder.image(source);
}
// Then use it:
const imageUrl = urlFor(product.image)
.width(800)
.height(600)
.url();The image URL builder automatically respects the hotspot and crop data when you pass in the full image object from your Sanity query.
Handling Hotspot with CSS
Sometimes the hotspot doesn't apply perfectly with certain Next.js layouts. In those cases, you can manually apply it using CSS object-position:
function getPositionFromHotspot(hotspot) {
if (!hotspot?.x || !hotspot?.y) return "center";
return `${hotspot.x * 100}% ${hotspot.y * 100}%`;
}
<Image
src={urlFor(image).url()}
alt={image.alt}
fill
style={{
objectFit: 'cover',
objectPosition: getPositionFromHotspot(image.hotspot)
}}
/>Don't Forget Next.js Config
Make sure your next.config.js allows loading images from Sanity's CDN:
module.exports = {
images: {
domains: ['cdn.sanity.io']
}
};Query the Right Data
When fetching your product data, make sure you're including the image metadata, hotspot, and crop information:
const query = `*[_type == "product"] {
image {
asset->{
...,
metadata
},
hotspot,
crop
}
}`;The next-sanity-image package handles most of the complexity for you and is the recommended approach for e-commerce sites where you need consistent, responsive product images. It automatically generates the right srcSet values and respects Sanity's image transformations, which is exactly what you need for an e-commerce platform.
Let me know if you're still running into issues after trying these approaches!
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.