
Content Modeling Best Practices
Apply Sanity content-modeling reuse patterns so testimonials, SEO blocks, and page builders stay DRY while you ship a headless CMS schema.
Overview
Content Modeling Best Practices is an agent skill for the Build phase that guides Sanity schema design using shared components and shared field sets to maximize reuse and limit duplication.
Install
npx skills add https://github.com/sanity-io/agent-toolkit --skill content-modeling-best-practicesWhat is this skill?
- Maps a duplication-to-reference spectrum so you choose copy vs link tradeoffs per field
- Pattern 1: standalone testimonial documents referenced from pageBuilder arrays
- Pattern 2: shared field sets (e.g. seoTitle, seoDescription, ogImage) spread across page and post types
- Uses Sanity defineType and defineField with reference types in pageBuilder blocks
- Targets agent-assisted schema refactors without duplicating SEO or social metadata on every type
- Documents a content reuse spectrum from full duplication to full reference
- Includes Pattern 1 (shared components via references) and Pattern 2 (shared field sets)
Adoption & trust: 2.4k installs on skills.sh; 150 GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
Your Sanity project copies testimonials, CTAs, and SEO fields into every document type, so updates require painful multi-type edits and inconsistent content in the studio.
Who is it for?
Solo builders on Sanity who are adding page builders, blogs, or marketing pages and want DRY schemas before the type list explodes.
Skip if: Projects not on Sanity, one-page static sites with no CMS, or teams that already finalized an approved content model and only need deployment automation.
When should I use this skill?
Designing or refactoring Sanity content types, page builders, or shared SEO/social metadata where duplication is creeping in.
What do I get? / Deliverables
You get reference-based reusable blocks and exportable field sets you can spread across types, yielding a cleaner content model ready for GROQ and frontend consumption.
- Reusable defineType snippets for shared components and field sets
- Reference-backed pageBuilder block definitions aligned to reuse patterns
Recommended Skills
Journey fit
Canonical shelf is Build because the skill encodes TypeScript Sanity schema work (defineType, defineField, references)—the phase where solo builders implement headless CMS integrations. Integrations fits headless CMS wiring: embedding referenced documents in page builders and sharing field sets across document types is integration-layer modeling, not generic frontend UI.
How it compares
Sanity-specific modeling patterns in procedural SKILL.md form—not a generic headless CMS tutorial or an MCP server for live dataset queries.
Common Questions / FAQ
Who is content-modeling-best-practices for?
Indie and solo developers using Sanity who model documents in TypeScript and want agent help applying reuse patterns for testimonials, SEO, and shared blocks.
When should I use content-modeling-best-practices?
Use it in Build while designing or refactoring schemas—especially when adding pageBuilder sections, new post types, or shared SEO fields—and during Validate when scoping how content will be structured before implementation.
Is content-modeling-best-practices safe to install?
Treat it like any third-party agent skill: review the Security Audits panel on this Prism page and inspect the SKILL.md in your repo before letting an agent edit production schema files.
SKILL.md
READMESKILL.md - Content Modeling Best Practices
# Content Reuse Patterns Effective content models maximize reuse while minimizing duplication. Here are patterns for achieving both. ## The Content Reuse Spectrum ``` Full Duplication ←————————————————→ Full Reference (Copy everything) (Link to one source) ``` Most real-world content sits somewhere in between. ## Pattern 1: Shared Components Create reusable content blocks that can be embedded anywhere. **Use case:** Testimonials, FAQs, CTAs that appear on multiple pages. ```typescript // Standalone testimonial documents defineType({ name: 'testimonial', type: 'document', fields: [ defineField({ name: 'quote', type: 'text' }), defineField({ name: 'author', type: 'string' }), defineField({ name: 'company', type: 'string' }), ] }) // Reference in page builders defineField({ name: 'pageBuilder', type: 'array', of: [ { type: 'reference', to: [{ type: 'testimonial' }] } ] }) ``` ## Pattern 2: Shared Field Sets Extract common fields into reusable definitions. **Use case:** SEO fields, social metadata, common dates. ```typescript // Shared field definition export const seoFields = [ defineField({ name: 'seoTitle', type: 'string' }), defineField({ name: 'seoDescription', type: 'text' }), defineField({ name: 'ogImage', type: 'image' }), ] // Spread into multiple types defineType({ name: 'page', fields: [ defineField({ name: 'title', type: 'string' }), ...seoFields ] }) defineType({ name: 'post', fields: [ defineField({ name: 'title', type: 'string' }), ...seoFields ] }) ``` ## Pattern 3: Taxonomy References Centralize classification for consistent tagging. **Use case:** Categories, tags, topics that span content types. ```typescript // Central taxonomy defineType({ name: 'category', type: 'document', fields: [ defineField({ name: 'title', type: 'string' }), defineField({ name: 'slug', type: 'slug' }), ] }) // Used across content types defineField({ name: 'categories', type: 'array', of: [{ type: 'reference', to: [{ type: 'category' }] }] }) ``` ## Pattern 4: Content Fragments Small, reusable pieces that combine into larger content. **Use case:** Bios, addresses, contact info. ```typescript // Fragment type defineType({ name: 'contactInfo', type: 'object', fields: [ defineField({ name: 'email', type: 'email' }), defineField({ name: 'phone', type: 'string' }), defineField({ name: 'address', type: 'text' }), ] }) // Reused across types defineType({ name: 'office', fields: [ defineField({ name: 'name', type: 'string' }), defineField({ name: 'contact', type: 'contactInfo' }), ] }) ``` ## Anti-Pattern: Over-Abstraction Not everything needs to be reusable. If content is only used in one place, embedding is simpler. **Signs of over-abstraction:** - References that are only used once - Editors navigating multiple documents for one page - Complex queries joining rarely-shared content # Reference vs Embedding Content When should content be linked (referenced) vs copied (embedded)? This decision affects reusability, query complexity, and editing workflows. ## The Trade-offs | Aspect | Reference | Embedded Object | |--------|-----------|-----------------| | Reusability | ✅ Shared across documents | ❌ Copied per document | | Single source | ✅ Update once, reflects everywhere | ❌ Must update each copy | | Query complexity | Requires joins/expansion | Inline, simpler queries | | Editing UX | Separate editing interface | All fields in one place | | Independence | Can exist on its own | Only exists within parent | ## When to Reference Use references when content: - **Is reusable** — Same author across many articles - **Needs central management** — Update product info once - **Has its own lifecycle** — Published/draft independent of parent - **Should stay in sync** — Price changes reflect everywhere **Examples:** - Author profiles - Product catalog items - Shared testimonials - Cat