# Rendering assets https://www.sanity.io/learn/course/day-one-with-sanity-studio/rendering-assets.md Sanity's powerful image asset CDN allows you to deliver images at the appropriate size by setting a few query parameters on a URL. 1. Read [Presenting Images](https://www.sanity.io/learn/apis-and-sdks/presenting-images) in the documentation for more details To simplify the creation of image URLs, we also ship a number of helpful functions and methods in the `@sanity/image-url` package. 1. **Run** the following to install `@sanity/image-url` ```sh # in apps/web pnpm add @sanity/image-url ``` ## Configure image domains Next.js includes an `Image` component for the performant rendering of images. Before you can use images from Sanity's CDN URL they'll need to be added to the Next.js configuration. 1. Read more about the `Image` component [in the Next.js documentation](https://nextjs.org/docs/app/api-reference/components/image). 1. **Update** `next.config.ts` to include the URLs of Sanity's CDN and a placeholder service. ```javascript:apps/web/next.config.ts import type { NextConfig } from "next"; const nextConfig: NextConfig = { images: { remotePatterns: [ { protocol: "https", hostname: "cdn.sanity.io" }, { protocol: "https", hostname: "placehold.co" }, ], }, }; export default nextConfig; ``` ## Building image URLs Create a helper function that is specific to your project ID and dataset which takes information about an image asset in Sanity (such as its ID) and return a complete URL with settings such as quality and size. 1. **Create** a new file to export a `urlFor` helper function ```typescript:apps/web/src/sanity/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); } ``` You can now update the individual page route to use Image component from Next.js as well as this `urlFor` function to turn a Sanity image asset ID into a complete URL. ```tsx:apps/web/src/app/events/[slug]/page.tsx import { defineQuery, PortableText } from "next-sanity"; import Link from "next/link"; import { notFound } from "next/navigation"; import Image from "next/image"; import { sanityFetch } from "@/sanity/live"; import { urlFor } from "@/sanity/image"; const EVENT_QUERY = defineQuery(`*[ _type == "event" && slug.current == $slug ][0]{ ..., "date": coalesce(date, now()), "doorsOpen": coalesce(doorsOpen, 0), headline->, venue-> }`); export default async function EventPage({ params, }: { params: Promise<{ slug: string }>; }) { const { data: event } = await sanityFetch({ query: EVENT_QUERY, params: await params, }); if (!event) { notFound(); } const { name, date, headline, details, eventType, doorsOpen, venue, tickets, } = event; const eventDate = new Date(date).toDateString(); const eventTime = new Date(date).toLocaleTimeString(); const doorsOpenTime = new Date( new Date(date).getTime() - doorsOpen * 60000 ).toLocaleTimeString(); const imageUrl = headline?.photo ? urlFor(headline.photo) .height(310) .width(550) .quality(80) .auto("format") .url() : "https://placehold.co/550x310/png"; return (
← Back to events
{name
{eventType ? (
{eventType.replace("-", " ")}
) : null} {name ? (

{name}

) : null} {headline?.name ? (
Artist
{headline?.name}
) : null}
Date
{eventDate &&
{eventDate}
} {eventTime &&
{eventTime}
}
{doorsOpenTime ? (
Doors Open
Doors Open
{doorsOpenTime}
) : null} {venue?.name ? (
Venue
{venue.name}
) : null}
{details && details.length > 0 && (
)} {tickets && ( Buy Tickets )}
); } ``` You can now open any event with a `headline` artist with a `photo` field, and see the image rendered at the appropriate size. ![Artist page with a photo rendered](https://cdn.sanity.io/images/3do82whm/next/82005b7f36c6ab812d748e786e266aca600f8aa8-2240x1480.png) 1. Set `hotspot: true` on the `image` field schema to enable crop and hotspot. When this data is passed into the same URL builder function it is added to the image URL parameters. ```typescript:apps/studio/schemaTypes/artistType.ts defineField({ name: 'photo', type: 'image', options: { hotspot: true }, }), ``` You're now querying and rendering text and image content from Sanity into your Next.js application—but your code has some annoying red squiggly lines because of TypeScript. Let's fix that next.