I'm hoping for a bit of schema setup/structure guidance.

2 replies
Last updated: Nov 17, 2020
Hi Sanity community.
I m hoping for a bit of schema setup/structure guidance. I have a loose model of a cms in place.
Page
being a top level document. A page has an array of
Component
documents. The intention is each page can use some prebuilt/specified "components" such as a 'hero' section. The hero section would have a predefined schema. ie: image, text, cta etc. In relational land I'd imagine some sort of an instance of a component being created when a component is added to a page of type hero.
Any suggestions on how to set this up effectively would be greatly appreciated.

Thank you in advance.
AI Update

Based on what you're describing, you're on the right track! This is a classic page builder pattern in Sanity, and there are a couple of ways to structure it depending on your needs.

The Two Main Approaches

You have two architectural options for connecting components to pages:

1. Inline Objects (Most Common)

Define your components as object types and embed them directly in the page's array. This is like having the component data live "inside" the page document:

// Component schemas (objects, not documents)
export const hero = {
  name: 'hero',
  type: 'object',
  fields: [
    {name: 'heading', type: 'string'},
    {name: 'image', type: 'image'},
    {name: 'cta', type: 'object', fields: [...]},
  ]
}

// Page schema
export const page = {
  name: 'page',
  type: 'document',
  fields: [
    {name: 'title', type: 'string'},
    {
      name: 'content',
      type: 'array',
      of: [
        {type: 'hero'},
        {type: 'features'},
        {type: 'faq'},
        // ... other component types
      ]
    }
  ]
}

Pros: Simpler queries, content stays with the page, easier to manage
Cons: Can't reuse the exact same hero instance across multiple pages

2. References to Documents

Make your components actual documents and reference them:

// Component as document
export const hero = {
  name: 'hero',
  type: 'document',
  fields: [...]
}

// Page references components
export const page = {
  name: 'page',
  type: 'document',
  fields: [
    {
      name: 'content',
      type: 'array',
      of: [{type: 'reference', to: [{type: 'hero'}, {type: 'features'}]}]
    }
  ]
}

Pros: Can reuse exact component instances across pages
Cons: More complex queries (need to resolve references), more documents to manage

Recommendation

For most page builders, go with inline objects (approach #1). This matches your "instance of a component" mental model from relational databases - each time you add a hero to a page, you're creating a new instance with its own data.

The Sanity page building course covers this exact pattern in detail and shows how to structure your component schemas, add custom previews so editors see what they're building, and handle rendering on the frontend.

Only use references if you specifically need to share the exact same content across multiple pages (like a global announcement banner that should update everywhere when changed).

Additional Tips

  • Give each component type a good title and preview configuration so content editors can easily identify blocks
  • Consider adding an icon property to each component type for better visual scanning in the Studio
  • You can mix both approaches - some components as objects, others as references - if that fits your use case

The beauty of this approach is that adding a new component type just means adding it to the of array, and it immediately becomes available to all pages!

user N
you might get some ideas from this article:

https://www.sanity.io/guides/how-to-use-structured-content-for-page-building
You could create objects for your “components” and then have them available in an array so you can add and relocate them as-needs.

Hope this helps?!
O great. This looks very close to what I m trying to do. Thanks!

Sanity – Build the way you think, not the way your CMS thinks

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.

Was this answer helpful?