Trouble with client.fetch() in Next.js 13 directory
This is a common issue when using Sanity with Next.js 13's app directory! The problem is likely related to how you're configuring your Sanity client. Let me walk through the most common causes and solutions.
Common Causes
1. CORS Configuration (Most Likely for Client Components)
If you're using client.fetch() in a client component (marked with 'use client'), you need to add your localhost origin to your Sanity project's CORS settings. The reason jsonplaceholder works is because their API allows all origins, but Sanity requires explicit domain whitelisting for browser-based requests.
To fix this:
- Go to manage.sanity.io
- Select your project
- Navigate to Settings > API > CORS Origins
- Add
http://localhost:3000(or whatever port you're using) - If you're using authentication tokens, check the "Allow credentials" box
This is covered in the CORS Origins documentation.
2. Dataset Privacy Settings
Your dataset might be set to private, which requires an API token for read access. Check your dataset settings at manage.sanity.io. If it's private, you'll need to:
- Create a read token in your project's API settings
- Add it to your client configuration:
import { createClient } from 'next-sanity'
export const client = createClient({
projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,
dataset: process.env.NEXT_PUBLIC_SANITY_DATASET,
apiVersion: '2024-01-01',
useCdn: true,
token: process.env.SANITY_API_TOKEN, // Only needed if dataset is private
})Note: If your dataset is public (which is common for production websites), you don't need a token for read operations.
3. Incorrect Client Configuration
Make sure your client is properly configured. For Next.js 13+ app directory with Server Components (the default), you should use the next-sanity package:
npm i next-sanityThen create a sanity/client.ts file:
import { createClient } from 'next-sanity'
export const client = createClient({
projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID!,
dataset: process.env.NEXT_PUBLIC_SANITY_DATASET!,
apiVersion: '2024-01-01', // Use current date
useCdn: true, // Set to false if you want fresh data
})4. Using sanityFetch (Recommended)
For better caching and performance in Next.js 13+ app directory, consider using the sanityFetch helper from next-sanity instead of client.fetch(). It provides automatic cache configuration and works seamlessly with React Server Components:
import { sanityFetch } from './sanity/client'
const posts = await sanityFetch({
query: `*[_type == "post"]`,
tags: ['post'], // For cache revalidation
})Debugging Steps
- Check the error message: Look in your browser console for specific CORS errors or authentication errors
- Verify environment variables: Make sure your
NEXT_PUBLIC_SANITY_PROJECT_IDandNEXT_PUBLIC_SANITY_DATASETare correctly set - Test with a simple query: Try a basic query like
*[_type == "post"][0..2]to isolate the issue - Check dataset permissions: Verify in manage.sanity.io whether your dataset is public or private
The key difference from jsonplaceholder is that Sanity has security measures in place - CORS restrictions for browser requests and optional authentication for private datasets. Once you configure these properly, client.fetch() will work just as reliably!
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.