Sanity
The structured content platform with a real-time collaborative editing studio (Sanity Studio). Best-in-class content modeling, GROQ query language, and live preview integrations.
Why Sanity?
Teams that need real-time collaborative content editing
Complex content models with custom input components
Next.js projects with live preview and draft mode
Signal Breakdown
What drives the Trust Score
Download Trend
Last 12 months
Tradeoffs & Caveats
Know before you commitNon-technical content teams — Contentful's UI is simpler
Self-hosted requirement — Sanity API is hosted
Very high API usage — costs scale with reads/writes
Pricing
Free tier & paid plans
2 users · 500k API calls/mo · 10GB assets
From $15/user/mo
Studio is always open-source
Alternative Tools
Other options worth considering
The leading headless CMS for enterprise content teams. API-first content infrastructure with a powerful content modeling system, webhooks, and SDKs for any frontend framework.
Often Used Together
Complementary tools that pair well with Sanity
Learning Resources
Docs, videos, tutorials, and courses
Get Started
Repository and installation options
View on GitHub
github.com/sanity-io/sanity
npm create sanity@latestnpm install @sanity/clientQuick Start
Copy and adapt to get going fast
import { createClient, groq } from '@sanity/client';
const client = createClient({
projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID!,
dataset: 'production',
useCdn: true,
apiVersion: '2024-01-01',
});
const POSTS_QUERY = groq`*[_type == "post"] | order(publishedAt desc)[0...10] {
_id, title, "slug": slug.current, publishedAt
}`;
const posts = await client.fetch<Post[]>(POSTS_QUERY);Code Examples
Common usage patterns
Next.js with live preview
Sanity draft mode + live preview in Next.js
// app/api/draft/route.ts
import { draftMode } from 'next/headers';
import { redirect } from 'next/navigation';
export async function GET(req: Request) {
const { searchParams } = new URL(req.url);
const secret = searchParams.get('secret');
const slug = searchParams.get('slug');
if (secret !== process.env.SANITY_PREVIEW_SECRET) {
return new Response('Invalid token', { status: 401 });
}
(await draftMode()).enable();
redirect(`/blog/${slug}`);
}GROQ with joins
Query related content with GROQ joins
import { createClient, groq } from '@sanity/client';
const client = createClient({ projectId: '...', dataset: 'production', apiVersion: '2024-01-01', useCdn: false });
// GROQ join: post → author → categories
const query = groq`*[_type == "post" && slug.current == $slug][0] {
title,
body,
"author": author-> { name, bio, "avatar": image.asset->url },
"categories": categories[]-> { title, slug },
publishedAt
}`;
const post = await client.fetch(query, { slug: 'hello-world' });Community Notes
Real experiences from developers who've used this tool