Query returns null for drafts in Next.js but works in Vision with token

9 replies
Last updated: Feb 20, 2023
Hello team! I need some help with a query that is returning posts if they are published but comes back with null if they are only drafts. What is weirder is that on the Vision pane it works but on my Nextjs client it doesn't. I am using a token with max permissions, that I generated in my project -> API -> Tokens, in my
sanity.client.ts
like this:
import { createClient } from "next-sanity";

export const projectId = process.env.NEXT_PUBLIC_SANITY_PROJECT_ID;
export const dataset = process.env.NEXT_PUBLIC_SANITY_DATASET;
export const apiVersion = process.env.NEXT_PUBLIC_SANITY_API_VERSION;
export const token = process.env.SANITY_SECRET_TOKEN;

export const client = createClient({
    projectId,
    dataset,
    apiVersion,
    useCdn: false,
    token
})
This is the query on my Nextjs, it works for published posts:

*[_type=='post' && slug.current == $slug][0]
        {
            ...,
            author->,
            categories[]-> 
        }
On the Vision pane if I do
*[_type=='post' && slug.current == $slug][0]
for the query and
{  "slug": "second-post" }
for the params (
second-post
is the slug for an unpublished post) it shows up. On my Nextjs it comes back null.
Has anybody encountered this?
AI Update

This is a classic issue with perspectives in Sanity's API! The Vision pane and your Next.js client are using different default perspectives, which is why you're seeing different results.

The Problem

By default, the Vision tool in Sanity Studio uses the previewDrafts perspective, which returns draft documents. However, when you query via the API from your Next.js app, it uses a different default perspective depending on your API version.

As of API version 2025-02-19, the default perspective changed to published, which means your queries will only return published documents unless you explicitly specify otherwise.

The Solution

You need to add the perspective option to your client configuration. Since you want to see drafts (and you already have a token with appropriate permissions), set it to previewDrafts:

import { createClient } from "next-sanity";

export const projectId = process.env.NEXT_PUBLIC_SANITY_PROJECT_ID;
export const dataset = process.env.NEXT_PUBLIC_SANITY_DATASET;
export const apiVersion = process.env.NEXT_PUBLIC_SANITY_API_VERSION;
export const token = process.env.SANITY_SECRET_TOKEN;

export const client = createClient({
    projectId,
    dataset,
    apiVersion,
    useCdn: false,
    token,
    perspective: 'previewDrafts'  // Add this line
})

The previewDrafts perspective will return draft versions when they exist, falling back to published versions when no draft exists. This matches the behavior you're seeing in Vision.

Alternative Approaches

If you want more control over when to show drafts vs published content, you could:

  1. Create two separate clients - one for published content and one for previews:
export const previewClient = createClient({
    projectId,
    dataset,
    apiVersion,
    useCdn: false,
    token,
    perspective: 'previewDrafts'
})

export const publicClient = createClient({
    projectId,
    dataset,
    apiVersion,
    useCdn: true,
    perspective: 'published'
})
  1. Use Next.js Draft Mode - Integrate with Next.js Draft Mode to conditionally switch between perspectives based on whether a user is previewing content.

Why This Happens

Draft documents in Sanity have an _id prefixed with drafts. (e.g., drafts.asdf-1234). The perspective setting controls whether queries include these draft documents in results. Without the proper perspective, your authenticated token alone isn't enough - the API still filters out drafts by default.

Show original thread
9 replies
I’m not 100% sure but you could update your query to something like this:

[_type=='post' && slug.current == $slug]
You have to drop the
[0]
as it only returns 1 result. When there is a draft, it returns two results of the query you’re working on.
Hi Dorell, thank you for your help. I don't think that is it, the [0] means that i only want the first item that corresponds to my $slug as i am using this query for an individual post page. I think the problem lies somewhere with the authentication of the query because if i do it in Vision it works
perhaps you might need to specify the client version
I actually got it to work!!
it was the token actually, i had generated a token with the wrong permissions.. im an idiot 🤦‍♂️
oh. glad to hear
you’ve made it work. not that you’re an idiot.
appreciate your help!! sorry for wasting your time
no problem

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.

Was this answer helpful?