
Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag storeI totally understand your challenge! Coming from WordPress with ACF, you're used to having page-specific fields. There are actually several approaches you can take in Sanity to solve this:
If your pages mostly share the same fields but need a few specific additions, you can use conditional fields to show/hide fields based on a page type or template selector:
{
name: 'page',
type: 'document',
fields: [
{
name: 'title',
type: 'string'
},
{
name: 'pageType',
type: 'string',
options: {
list: [
{title: 'About', value: 'about'},
{title: 'Team', value: 'team'},
{title: 'Projects', value: 'projects'},
{title: 'Contact', value: 'contact'}
]
}
},
// Team-specific field
{
name: 'teamMembers',
type: 'array',
of: [{type: 'reference', to: [{type: 'person'}]}],
hidden: ({document}) => document?.pageType !== 'team'
},
// Contact-specific field
{
name: 'contactForm',
type: 'object',
hidden: ({document}) => document?.pageType !== 'contact'
}
]
}This is the most popular approach and mirrors the ACF Flexible Content field. Instead of predefined fields, you give editors a toolkit of content blocks they can mix and match:
{
name: 'page',
type: 'document',
fields: [
{
name: 'title',
type: 'string'
},
{
name: 'content',
type: 'array',
of: [
{type: 'hero'},
{type: 'textBlock'},
{type: 'imageGallery'},
{type: 'teamGrid'},
{type: 'contactForm'},
{type: 'faqSection'}
]
}
]
}Each page can then compose its own layout. Your "Team" page might use [hero, textBlock, teamGrid] while "Contact" uses [hero, contactForm]. This gives you WordPress-like flexibility but with better structure.
If your pages are fundamentally different, create separate schemas:
// schemas/aboutPage.js
export default {
name: 'aboutPage',
type: 'document',
fields: [
{name: 'title', type: 'string'},
{name: 'history', type: 'text'},
{name: 'timeline', type: 'array', of: [{type: 'milestone'}]}
]
}
// schemas/contactPage.js
export default {
name: 'contactPage',
type: 'document',
fields: [
{name: 'title', type: 'string'},
{name: 'email', type: 'string'},
{name: 'phone', type: 'string'}
]
}Then in your frontend routing, query based on the slug or path to determine which document type to fetch.
For most sites, I'd go with option 2 (page builder with content blocks). It gives your editors the flexibility to create unique pages while maintaining consistency through reusable components. It's essentially what ACF's Flexible Content field does, but with better type safety and structure.
If you only need minor variations between pages, option 1 (conditional fields) is simpler and keeps everything in one schema.
Check out Sanity's page building course for a complete walkthrough of implementing the modular content block approach!
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.
Content operations
Content backend


The only platform powering content operations
By Industry


Tecovas strengthens their customer connections
Build and Share

Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag store