Best approach for retrieving translations in GROQ queries from frontend?
I can see you're hitting a frustrating issue where your translation query works in Studio but returns empty translations on the frontend. This is a common problem when working with document-level localization patterns, and the root cause is almost certainly related to API perspectives.
The Core Issue: Different Perspectives Between Studio and Frontend
Your Sanity Studio's Vision tool and your frontend Next.js app are likely querying different "views" of your content. The API version 2025-02-19 introduced a breaking change where the default perspective switched from raw to published. This means:
- Studio Vision: Often uses the
rawperspective by default, which shows all documents including drafts - Your frontend: If using a recent API version without explicitly setting a perspective, it defaults to
published, which only shows published documents
Since your path("i18n." + ^._id + ".*") pattern is looking for documents with specific ID patterns, if those translation documents aren't published (they're only drafts), they won't appear in your frontend results.
Quick Fix: Set Your Perspective Explicitly
Try explicitly setting the perspective in your frontend Sanity client:
import { createClient } from '@sanity/client'
const client = createClient({
projectId: 'your-project-id',
dataset: 'your-dataset',
apiVersion: '2024-01-01', // or your current version
perspective: 'previewDrafts', // Shows published + drafts, prioritizing drafts
useCdn: false, // Disable CDN while debugging
})The previewDrafts perspective will give you both published and draft documents, prioritizing drafts when both exist. You could also try perspective: 'raw' which shows all documents.
Verify Translation Document Publication Status
Your translation documents (those with i18n.* IDs) might exist only as drafts. To debug this, run a simple query from your frontend:
const result = await client.fetch('*[_id match "i18n.*"]')
console.log(result)If this returns empty but works in Studio, you've confirmed it's a perspective/publication issue. Make sure your translation documents are actually published (not just saved as drafts). In Sanity, draft documents have a drafts. prefix in their _id, and they won't appear in queries using the published perspective.
Systematic Debugging Steps
Verify document visibility: Run
*[_id match "i18n.*"]from your frontend with different perspectives:- With
perspective: 'published'(current default for newer API versions) - With
perspective: 'previewDrafts'(published + drafts, with drafts prioritized) - With
perspective: 'raw'(all documents)
- With
Check publication status in Studio: Go to your Studio and verify that your translation documents (the ones with
i18n.*IDs) are actually published. Look for the "Publish" button - if it's available, the document is still a draft.Disable CDN caching: Set
useCdn: falsetemporarily to ensure you're not hitting stale cached results.Compare Studio Vision configuration: Your Studio's Vision tool might be using a different perspective than your frontend. Check if there's a perspective selector in Vision.
Test with simpler queries first: Before running the complex translation query, make sure you can see the basic documents with
*[_type == "blog"]and the translation documents with*[_id match "i18n.*"].
About Your Query Pattern
The approach you're using with path("i18n." + ^._id + ".*") relies on document ID pattern matching, which is sensitive to perspective and publication state. The pattern itself is solid, but it requires that the documents it's looking for are visible in the perspective you're querying with.
Recommended Solution Path
For immediate debugging:
// In your frontend client configuration
const client = createClient({
// ... your existing config
perspective: 'previewDrafts',
useCdn: false,
})For production: Once you've confirmed the issue, decide on your approach:
- Option A: Ensure all translation documents are properly published, then use
perspective: 'published'in production - Option B: Use
perspective: 'previewDrafts'if you need to show draft translations in your frontend - Option C: Adjust your content workflow to better match your querying needs
The key insight here is that Studio and your frontend are querying different views of your content due to perspective differences. Studio's Vision tool often shows all documents (similar to raw perspective), while your frontend client—especially if using a recent API version—defaults to only published documents. This explains why you see translations in Studio but not in your Next.js app.
Show original thread8 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.