Fetching documents
Queries with parameters, direct document fetches, and the response envelope — including why a query should never be built by string concatenation.
A parameterised query
const post = await client.fetch(
`*[_type == "post" && slug.current == $slug][0]{
title,
publishedAt,
"author": author->{name, bio},
body
}`,
{ slug },
)Every value is a bound parameter. A GROQ query built by concatenation is the same class of mistake as SQL built by concatenation, and a slug arriving from a URL is exactly the untrusted input that makes it one.
Over HTTP directly
GET /api/v2026-07-26/data/query/production
?query=*%5B_type%20%3D%3D%20%22post%22%5D%7Btitle%7D
&%24slug=%22hello%22
&perspective=publishedPOST the same thing when the query is long enough to strain a URL:
curl -X POST "$HOST/api/v2026-07-26/data/query/production" \
-H 'content-type: application/json' \
-d '{"query":"*[_type == $type][0...5]{title}","params":{"type":"post"}}'One document by id
GET /api/v2026-07-26/data/doc/production/post-hello-new-orangeReturns { documents: [ … ] }. Useful when you already know the id; a query is the right tool for anything else.
The envelope
result— what the query evaluated to.ms— server-side duration.syncTags— the identifiers this result depends on. Use them as cache tags.resultSourceMap— emitted when asked for, and used by preview overlays to map a rendered value back to the field it came from. Partial: not every projection shape is mapped yet.
