
Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag storeYou definitely can auto-generate an excerpt from your blockContent field! The best approach is using the pt::text() function in your GROQ queries to extract plain text from Portable Text, which handles images, text blocks, and any other content automatically.
Instead of storing the excerpt as a separate field, generate it when you query your posts:
*[_type == "post"] {
title,
body,
"excerpt": pt::text(body)[0..96]
}The pt::text() function extracts all plain text from your Portable Text blocks, automatically handling whether your post starts with an image or text—exactly what you need! Then you can use array slicing ([0..96]) to limit it to the first 96 characters.
For a word-based excerpt instead of character-based, you can combine pt::text() with the string::split() function:
*[_type == "post"] {
title,
body,
"excerpt": array::join(string::split(pt::text(body), " ")[0..20], " ")
}This takes the first 20 words instead of cutting mid-word. Here's what's happening:
pt::text(body) extracts plain text from your Portable Textstring::split(pt::text(body), " ") splits it into an array of words[0..20] takes the first 20 wordsarray::join(..., " ") joins them back into a string with spacesIf you really want a stored excerpt field in your schema, you can use initialValue:
{
name: "excerpt",
title: "Excerpt",
type: "string",
initialValue: async ({document, getClient}) => {
if (!document?.body) return '';
const client = getClient({apiVersion: '2023-01-01'});
const result = await client.fetch(
`*[_id == $id][0]{"text": pt::text(body)}`,
{id: document._id}
);
return result?.text?.substring(0, 96) || '';
}
}However, this approach is more complex and has downsides—the excerpt won't update automatically when the body changes, and you'd need to manually re-save documents to refresh it.
The query-time approach using pt::text() is simpler and more maintainable because:
post.body[0] being an imageThe pt::text() function is specifically designed for this use case—extracting searchable, readable text from rich Portable Text content for things like excerpts, search indexing, and SEO meta descriptions.
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.
Content operations
Content backend


The only platform powering content operations
By Industry


Tecovas strengthens their customer connections
Build and Share

Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag store