Sanity CMS Setup
Working with Sanity Schemas
Every Propify component includes production-ready Sanity schemas. This guide explains how Sanity CMS works with Propify and how to integrate the schemas into your content workflow.
What is Sanity CMS?
Sanity is a flexible, API-first content platform that treats content as structured data. Unlike traditional CMSs, Sanity allows you to:
- Define custom content structures
- Collaborate in real-time
- Query content with GROQ
- Use content anywhere via APIs
Why Sanity + Propify?
The combination provides:
- Structured Content - Content that matches component props
- Type Safety - TypeScript types from schemas
- Visual Editing - Preview how content looks
- Team Collaboration - Multiple editors working together
- Version Control - Track content changes over time
Understanding Sanity Schemas
A Sanity schema defines the structure of your content:
export const heroSchema = defineType({ name: 'hero', title: 'Hero Section', type: 'document', fields: [ defineField({ name: 'headline', title: 'Headline', type: 'string', validation: Rule => Rule.required() }), defineField({ name: 'subheadline', title: 'Subheadline', type: 'text', rows: 3 }) ]})How Propify Schemas Work
Each Propify component schema:
- Matches the component props exactly
- Includes validation rules for data integrity
- Provides helpful descriptions for editors
- Supports preview configuration
- Uses consistent naming conventions
Example schema structure:
// Propify naming conventionexport const pricing05Module = defineType({ name: 'module.pricing05', // Namespaced name title: 'Pricing Cards', // Display name type: 'object', // Module type icon: IconComponent, // Visual identifier groups: [ // Organize fields { name: 'content', title: 'Content' }, { name: 'settings', title: 'Settings' } ], fields: [...] // Component props})Quick Integration Steps
1. Set Up Sanity Studio
# Create new Sanity projectnpm create sanity@latest# Or add to existing projectnpm install sanity2. Add Propify Schema
// schemas/modules/pricing05.tsimport { pricing05Module } from './propify/pricing05.schema'// schemas/index.tsexport const schemaTypes = [ pricing05Module, // ... other schemas]3. Use in Page Builder
defineType({ name: 'page', type: 'document', fields: [ defineField({ name: 'modules', type: 'array', of: [ { type: 'module.pricing05' }, // ... other modules ] }) ]})Querying Content
Use GROQ to fetch your component data:
// Basic queryconst query = `*[_type == "page" && slug.current == $slug][0]{ modules[]{ _type, _key, ... }}`;// Detailed query with expansionconst query = `*[_type == "page" && slug.current == $slug][0]{ modules[]{ _type == "module.pricing05" => { title, yearlyDiscount, plans[]{ name, price, features[] } } }}`;Type Safety with Sanity
Generate TypeScript types from your schemas:
// Use in your codeimport { Pricing05Module } from '@/sanity.types'function renderModule(module: Pricing05Module) { return <Pricing05 {...module} />}Content Modeling Best Practices
1. Keep It Flat
// Good - flat structurefields: [ { name: 'title', type: 'string' }, { name: 'price', type: 'number' }]// Avoid deep nesting when possible2. Use References
// Reference shared contentdefineField({ name: 'author', type: 'reference', to: [{ type: 'person' }]})3. Add Validation
defineField({ name: 'price', type: 'number', validation: Rule => Rule .required() .min(0) .error('Price must be positive')})Sanity Studio Customization
Enhance the editing experience:
// Custom input componentdefineField({ name: 'color', type: 'string', components: { input: ColorPickerInput }})// Conditional fieldsdefineField({ name: 'ctaUrl', type: 'url', hidden: ({ parent }) => !parent?.showCta})