Troubleshooting image rendering in Sanity.io, with guidance on resolving asset references and using @portabletext/react.
I can help you with this! The issue you're running into is a common one when working with images in Portable Text/Block Content. Without seeing your screenshot, I'm guessing you're getting an error about missing image data or undefined asset references.
The core problem is that when you query Block Content with images, you need to explicitly dereference the image asset in your GROQ query. By default, image references in Block Content are just references (like {_type: 'image', asset: {_ref: 'image-abc123-...'}}) - they don't include the actual image URL or metadata.
The Solution: Use the -> Dereference Operator
In your GROQ query, you need to expand the asset reference using the dereference operator (->). Here's the pattern:
*[_type == "yourDocumentType"] {
_id,
title,
body[]{
...,
_type == "image" => {
...,
asset->
}
}
}The key part is asset-> which tells GROQ to fetch the full asset document instead of just the reference.
More Complete Example
If you're also using custom marks or annotations, you might need something like this:
*[_type == "post"] {
_id,
title,
body[]{
...,
_type == "image" => {
...,
asset->{
_id,
url,
metadata {
lqip,
dimensions
}
}
},
markDefs[]{
...,
_type == "internalLink" => {
"slug": @.reference->slug.current
}
}
}
}Schema Side
Make sure your schema includes the image type properly:
defineField({
name: 'body',
type: 'array',
of: [
{
type: 'block'
},
{
type: 'image',
fields: [
{
name: 'alt',
type: 'string',
title: 'Alternative text'
}
]
}
]
})When Rendering
When you render the Portable Text on the frontend, make sure you have a custom serializer for images. The exact implementation depends on your framework, but here's a general pattern:
// Example with @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 || ''}
/>
),
},
}
// Then use it
<PortableText value={body} components={components} />The important thing is that once you've properly dereferenced the asset in your GROQ query with asset->, you'll have access to the full asset object with its URL and metadata, which you can then pass to Sanity's image URL builder or use directly.
Let me know if you're still stuck after trying the asset-> dereference - if you can share more details about the specific error message, I can help troubleshoot further!
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.