How to limit the number of documents for a schema in Sanity?

11 replies
Last updated: Jun 9, 2022
Hi 👋 first time with Sanity. It's so good! I was just wondering if it is possible to limit the amount of documents that any one schema can make … like here with only wanting one Home Page for example? Or a maximum of 2 say for another document?
AI Update

Welcome to Sanity! Glad you're enjoying it! 🎉

Yes, you can limit the number of documents for a schema type! For your home page example where you only want one document, you'll want to create what's called a singleton document. For limiting to a maximum number (like 2), there's a different approach.

Setting Up a Singleton (One Document Only)

To create a singleton, you need to configure three things in your sanity.config.ts file, as explained in the singleton document guide:

1. Structure Builder - Create a direct link to the single document:

export default defineConfig({
  // ... other config
  plugins: [
    structureTool({
      structure: (S) =>
        S.list()
          .title('Content')
          .items([
            S.listItem()
              .title('Home Page')
              .id('homePage')
              .child(
                S.document()
                  .schemaType('homePage')
                  .documentId('homePage')
              ),
            // ... other items
          ])
    })
  ]
})

2. Filter Templates - Remove it from the "New document" menu:

const singletonTypes = new Set(['homePage'])

export default defineConfig({
  // ... other config
  schema: {
    types: schemaTypes,
    templates: (templates) =>
      templates.filter(({ schemaType }) => !singletonTypes.has(schemaType))
  }
})

3. Filter Document Actions - Remove duplicate/delete actions:

const singletonActions = new Set(['publish', 'discardChanges', 'restore'])

export default defineConfig({
  // ... other config
  document: {
    actions: (input, context) =>
      singletonTypes.has(context.schemaType)
        ? input.filter(({ action }) => action && singletonActions.has(action))
        : input
  }
})

Important: Create the document instance first (before adding these configurations), since you're hiding the "create new" UI!

Limiting to a Maximum Number (Like 2 Documents)

For limiting to a specific maximum (not just one), you can use the document.newDocumentOptions configuration to dynamically hide the create button when the limit is reached. Here's an example:

export default defineConfig({
  // ... other config
  document: {
    newDocumentOptions: async (prev, { creationContext, getClient }) => {
      // Only filter for specific schema types
      const limitedTypes = ['testimonial', 'featuredPost']
      const limits = {
        testimonial: 2,
        featuredPost: 3
      }

      // Get filtered templates
      const filtered = await Promise.all(
        prev.map(async (template) => {
          const schemaType = template.templateId
          
          if (!limitedTypes.includes(schemaType)) {
            return template
          }

          // Query to count existing documents
          const client = getClient({ apiVersion: '2024-11-01' })
          const count = await client.fetch(
            `count(*[_type == $type])`,
            { type: schemaType }
          )

          // Hide template if limit reached
          if (count >= limits[schemaType]) {
            return null
          }

          return template
        })
      )

      return filtered.filter(Boolean)
    }
  }
})

This approach queries your dataset to count existing documents and hides the creation option when the limit is reached.

About Your Existing Data

As noted in this community answer, switching to the Structure Builder won't delete your existing content. Your studio already uses the Structure Builder—you're just not customizing it yet. However, for singleton documents, you may need to recreate them with the specific document ID you define in your structure configuration.

This singleton pattern is super common for things like site settings, home pages, about pages, and global configuration!

Show original thread
11 replies
Hi
user F
thank you! Can this only be done via the Structure Builder? My site is finished but it's a collection of documents with a Page Builder as the home page.
Yes, this can only be done via the structure builder. 🙂
Ah ok. Are there any plans to add this at the document level, or to Page Builder?
If I switched now to Structure Builder, would that delete all of the existing content?
I’m a little confused. You wouldn’t switch to the structure builder. Your studio is already using the structure builder. You’re just not customizing it, if you will. So if you were to start customizing it, you wouldn’t lose anything, but the way singleton documents work would mean you would need to redo your documents, yes. Because the idea is that you create the singleton manually in the structure builder configuration, and you disable the option to create them via the studio.
When in doubt, back up your dataset beforehand anyway.
🙂
Ah, I see thank you!
How do I backup my dataset?
Thank you!
I could redo my documents as there are only a few but would this also mean changing how I query the data? At the moment I get my data like this

export async function getStaticProps() {
  const data = await client.fetch(
    `
      *[_type in ["homePage"]]{
        _type == "homePage" => {
          pageBuilder[]->{...}
        }
      }
    `);

You can simplify your query a bit:
*[_type in "homePage"] {
  pageBuilder[]->
}
Your query would still work I think anyway.
🙂
Ah, sorry, I've actually got as I'm passing some data props to a footer and a modal…

export async function getStaticProps() {
  const data = await client.fetch(
    `
      *[_type in ["footer", "termsAndConditions", "homePage"]]{
        _type == "footer" => {
          ...
        },
        _type == "termsAndConditions" => {
          ...
        },
        _type == "homePage" => {
          pageBuilder[]->{...}
        }
      }
    `);

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?