I Designed My Schema Wrong for Months. Here’s What I Learned About Sanity (the Hard Way)
January 2026. I’d spent weeks on a Sanity content project that was starting to crack at the seams.
The editorial team kept messaging things like: “what does this field mean?” or “is this for mobile or desktop?”. And I had to explain it every time.
The problem wasn’t Sanity. The problem was me, modeling the schema like a traditional relational database form.
Here’s what I learned, straight to the point.
The Mistake Everyone Makes: Booleans Where They Shouldn’t Be
Here’s the typical field you see in almost every project:
Seems reasonable, right? Published or not published.
The problem is that content isn’t binary in real life. You have drafts, revisions, published, archived, scheduled. And when you add a second boolean isFeatured, and a third isArchived, you’ve got a combination of inconsistent states that nobody on the team understands.
The right pattern is string literals:
Now the state is explicit, extensible, and self-documenting. When you need to add scheduled three months from now, you add it to the array. No weird migrations, no ambiguity.
Field Groups: The Schema the Editorial Team Actually Understands
When a document has twenty fields, editors get lost. Field Groups cluster fields by context, not by technical type.
The writer sees “Content” first. The SEO manager goes to their tab. The developer configures in “Settings”. Everyone in their context. The “I can’t find the field” messages practically disappear.
Custom Previews: The Feature Nobody Configures (That Saves Hours)
By default, Studio shows the first text field as the document title in the list view. With complex documents, that gives you useless lists full of “undefined” or “No title”.
Now the document list in Studio shows the status with an emoji, the title, and the cover image. The editorial team knows at a glance what’s pending review without opening each document.
Validation Rules: Protecting the Team From Themselves
This is genuinely great. Sanity allows synchronous and asynchronous validations directly in the schema.
The difference between .error() and .warning() is key: errors block publishing, warnings inform without blocking. You guide without frustrating.
For more complex fields, async validations even allow external calls — though I reserve those for specific cases where the request cost is justified.
GROQ and Schema: The Connection People Ignore
What you define in the schema determines how you write your GROQ queries. When you use string literals instead of multiple booleans, your queries get cleaner:
coalesce() is one of the GROQ functions I use most: returns the first non-null value. Here it uses the manual excerpt if it exists; otherwise, it automatically extracts the first characters of the body.
The score() function (or _score operator with match) is Sanity’s native way to do relevance search. No external services, no extra configuration.
The Image Pipeline: What Eliminated a Significant Monthly Bill
Before properly understanding Sanity, I was using an external image optimization service. The problem was I was paying for transformations that Sanity’s native pipeline already includes.
Sanity stores hotspot and crop metadata directly in the asset:
With @sanity/image-url you build optimized URLs on the fly:
The lqip (Low Quality Image Placeholder) field comes included in the asset metadata. Native blur placeholder with zero extra configuration.
Real-Time Previews: The Bridge That Ends the Tug-of-War With the Editorial Team
This solved a repetitive cycle: the writer would publish, see how it looked in production, request changes, I’d make them, repeat.
With useLiveQuery from next-sanity and Next.js Draft Mode, the Studio shows changes in real time on the site before publishing:
The writer sees changes as they type. No deploys, no screenshots, no Slack with attachments. Game-changer.
What Changes When You Design the Schema Right
Sanity has a generous free tier (20 seats, 500K API requests per month) that covers most small and medium projects. But the real value isn’t in the pricing — it’s in the time you save when the schema is well-designed from the start.
Schema decisions are the cheapest decisions you make in a content project. Changing them later is expensive. Changing them when you have thirty thousand indexed documents is very expensive.
Here are the concrete steps to apply this week:
- Audit your booleans. If you have more than two status booleans on a document, consolidate them into a string literal with explicit options.
- Enable Field Groups on any document with more than eight fields. Group by audience (editorial, SEO, technical), not by data type.
- Add custom preview to all your main types. Include status with a visual indicator.
- Validate SEO fields with character ranges. Block publishing if meta description is empty.
- Enable hotspot on all your images and verify you’re using
lqipfor blur placeholders.
Keep building.
