How to query images from portable text body in Sanity slug page?
It sounds like you're trying to query images that are embedded inside a Portable Text body field in your blog posts, but you're getting a "ReferenceError: image is not defined" error. This is a common issue when working with Sanity's Portable Text and images.
The problem is likely that when you query your blog post, the image references inside the body field aren't being "expanded" - they're just coming back as reference objects rather than the full image data you need.
The Solution: Use GROQ to Expand Image References
When you have images inside a Portable Text field (like your body array), you need to use GROQ's projection syntax to "materialize" or expand those image asset references. Here's how to do it:
*[_type == "post" && slug.current == $slug][0] {
title,
body[]{
...,
_type == "image" => {
...,
asset->
}
}
}Let me break this down:
body[]- iterate through each block in the body array...- spread all the existing properties_type == "image" => { ... }- when you encounter an image block, expand itasset->- follow the asset reference to get the full image document
For Next.js (getStaticProps or similar)
If you're using this in a [slug].js file with Next.js, your query might look like:
export async function getStaticProps({ params }) {
const query = `*[_type == "post" && slug.current == $slug][0] {
title,
body[]{
...,
_type == "image" => {
...,
asset->{
_id,
url,
metadata {
dimensions
}
}
}
}
}`
const post = await client.fetch(query, { slug: params.slug })
return {
props: { post }
}
}Rendering the Images
Once you have the expanded data, you can render images in your Portable Text using @portabletext/react:
import { PortableText } from '@portabletext/react'
import imageUrlBuilder from '@sanity/image-url'
const builder = imageUrlBuilder(client)
const components = {
types: {
image: ({ value }) => (
<img
src={builder.image(value).width(800).url()}
alt={value.alt || ' '}
/>
)
}
}
export default function Post({ post }) {
return (
<PortableText
value={post.body}
components={components}
/>
)
}The key issue was that you need to explicitly expand the image asset references in your GROQ query using the asset-> syntax. Without this, you just get a reference object, not the actual image data you need to display the image.
Check out the official Sanity docs on Block Content image materializing for more details on this pattern!
Show original thread25 replies
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.