Use Sanity with Next.js

Rendering images in Next.js with next-sanity

Reference for the Image component and imageLoader exported from next-sanity/image. Wraps next/image with a Sanity CDN-aware loader.

The next-sanity library exports an Image component and imageLoader function that integrate Sanity's image CDN with the Next.js next/image component. Pass a Sanity CDN URL as the src prop and the component handles format negotiation, responsive sizing, and aspect ratio preservation automatically.

Installation

The Image component and imageLoader require next-sanity 8.3.0 or later. The current major version, next-sanity 13, requires Next.js 16, React 19.2.3 or later, and sanity 5.29.0 or later.

If you don’t already have them, install next-sanity and @sanity/image-url.

npm install next-sanity @sanity/image-url

Basic usage

The Image component accepts a Sanity CDN URL string as its src prop. Use @sanity/image-url to build the URL from your image data (see Build the source URL), then pass it to Image:

import type { SanityImageSource } from '@sanity/image-url'
import { Image } from 'next-sanity/image'
import { urlFor } from '@/sanity/lib/image'

export function AuthorPhoto({ image }: { image: SanityImageSource }) {
  return (
    <Image
      src={urlFor(image).url()}
      alt="Author photo"
      width={400}
      height={300}
    />
  )
}

How this differs from the next/image component

The Image component from next-sanity/image wraps next/image, so you get the same developer-facing features: lazy loading, srcSet generation, preloading, and layout stability. The difference is in where and how image optimization happens.

With the next-sanity/image component, the built-in loader bypasses the Next.js optimization proxy entirely. Instead, it constructs a URL that points directly to Sanity's image CDN with the right transformation parameters. Sanity's CDN handles resizing, format conversion, and caching at the edge. This means:

  • No remotePatterns configuration is needed in next.config.js for Sanity images.
  • Format negotiation (WebP, AVIF) happens at the CDN level through the auto=format parameter, based on the browser's Accept header.
  • Your Next.js server doesn't process the images, reducing its CPU and memory load.
  • The loader automatically maintains aspect ratio across srcSet breakpoints by recalculating the h parameter proportionally for each width.
  • The loader sets sensible defaults for the fit parameter: fit=max when only width is specified (prevents upscaling), fit=min when both width and height are present.

There are a couple of tradeoffs. The Image component restricts src to a string (it must be a valid Sanity CDN URL), while next/image also accepts static imports. It also disallows the loader prop since it ships with its own. If you need a custom loader or want to use the default Next.js optimization proxy, use next/image directly.

How the loader works

The built-in imageLoader transforms the Sanity CDN URL for each entry in the generated srcSet. For every width that next/image requests, the loader:

  • Sets auto=format so the CDN returns the best format the browser supports (WebP, AVIF). See Image transformations for the full list of URL parameters.
  • Sets fit=max when only width is specified, or fit=min when both width and height are present. If the URL already contains a fit parameter, the loader respects it.
  • Recalculates h proportionally when both w and h are present, preserving the original aspect ratio at each breakpoint.
  • Passes the quality prop through as the q URL parameter.

This means your images are served in the optimal format and size without additional configuration.

Props

ImageProps extends all next/image props except loader and changes src to accept only a string.

  • Requiredsrc

    string

    A valid Sanity image CDN URL. Build this with @sanity/image-url or construct it manually. If src isn't a valid absolute URL, the component throws a TypeError: The `src` prop must be a valid URL to an image on the Sanity Image CDN.

  • width

    number

    Width in pixels. Appended as w to the URL and used by the loader for aspect ratio calculations.

  • height

    number

    Height in pixels. Appended as h to the URL and used by the loader for aspect ratio calculations.

  • quality

    number

    Image quality (0-100). Passed through as q to the Sanity CDN.

  • loader

    never

    Not supported. If you pass a custom loader, the component throws a TypeError: The `loader` prop is not supported on `Image` components. Use `next/image` directly to use a custom loader.

All other next/image props, such as alt, preload, fill, sizes, placeholder, and className, are passed through to the underlying next/image component.

Use the image loader with the next/image component

If you need more control over the next/image component but still want Sanity CDN URL handling, you can use the exported imageLoader directly with next/image:

import type { SanityImageSource } from '@sanity/image-url'
import NextImage from 'next/image'
import { imageLoader } from 'next-sanity/image'
import { urlFor } from '@/sanity/lib/image'

export function CustomImage({ image }: { image: SanityImageSource }) {
  return (
    <NextImage
      loader={imageLoader}
      src={urlFor(image).width(800).height(600).url()}
      alt="Product photo"
      width={800}
      height={600}
      sizes="(max-width: 768px) 100vw, 800px"
    />
  )
}

Unlike the Image component, imageLoader doesn't add the width and height props to the URL. Set both dimensions on the URL builder too, as this example does with .width(800).height(600), so the loader can recalculate h and keep the aspect ratio at each srcSet width. Use this approach when you want to wrap imageLoader in your own loader function, for example to add URL parameters. Because the loader prop takes a function, define a custom wrapper loader in a file that starts with 'use client'.

Build the source URL

The Image component expects a Sanity CDN URL string, not a Sanity image reference object. Use @sanity/image-url to build it. See Presenting images for full setup instructions:

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

const builder = createImageUrlBuilder(client)

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

The URL builder respects crop and hotspot settings when you pass the full image object (not just the asset reference). The hotspot is applied only when you set both width() and height() on the builder. You can chain additional transformations before calling .url():

// Crop and hotspot are applied automatically
<Image
  src={urlFor(post.mainImage).width(1200).height(675).url()}
  alt={post.mainImage.alt || ''}
  width={1200}
  height={675}
  preload
/>

Relationship to the @sanity/image-url package

These two tools serve different purposes and work together:

  • @sanity/image-url builds a Sanity CDN URL string from image data. It handles crop, hotspot, and transformation parameters.
  • next-sanity/image takes that URL string and integrates it with next/image so you get automatic srcSet generation, format negotiation, and responsive loading from the Sanity CDN.

You can use @sanity/image-url without next-sanity/image (for example, with a plain <img> tag or a different framework's image component). But when using Next.js, the Image component from next-sanity/image gives you the best of both: Sanity CDN transformations with next/image optimizations.

Related resources

  • Presenting images: configuring @sanity/image-url, crop and hotspot, responsive images, and performance tips.
  • Image transformations: full reference for Sanity CDN URL parameters (w, h, fit, auto, q, and more).
  • Image metadata: LQIP placeholders, dimensions, palette, and other metadata available for Sanity images.
  • Image schema type: schema configuration for image fields, including crop and hotspot options.

Was this page helpful?

Sanity logosanity.ioAll Systems Operational© Sanity 2026
Change site theme