How to create self-referencing schemas in Sanity without circular references?

2 replies
Last updated: Jan 28, 2026
Does anyone know how you reference a schema from a schema? (i.e. self-referencing).
If a section can have children and one type of child can again be a [nested] section, how do you do that in the schema without creating a circular reference? Is this the right way?


export default defineType({
  name: "section",
  title: "Section",
  type: "object",
  fields: [

    defineField({
      type: "array",
      name: "blocks",
      title: "Content",
      of: [

        defineArrayMember(codeBlock), // <-- You can't do this with section because of circular reference
        
        defineArrayMember({ // <-- SO is this what you're supposed to do?
          name: "section",
          title: "Section",
          type: "section",
        }),

      ],
    }),

  ],

});
AI Update

Yes, exactly! The approach you're showing in your second example is the correct way to handle self-referencing schemas in Sanity. You reference the schema type by its name as a string.

Your code is spot-on:

defineArrayMember({
  name: "section",
  title: "Section",
  type: "section", // <-- This string reference prevents circular dependency issues
})

This works because Sanity's schema system resolves type references by name at runtime, not at definition time. When you use type: "section" as a string, you're telling Sanity "look up the type named 'section' when you need it" rather than trying to import and nest the actual schema object directly.

Why this works

The key difference is:

  • Importing the schema object directly (like defineArrayMember(section)) would create a circular JavaScript module dependency
  • Referencing by type name (like type: "section") lets Sanity's schema registry handle the lookup after all schemas are loaded

This pattern works for any self-referencing or mutually-referencing schemas. You can have deeply nested structures like sections within sections within sections, and Sanity will handle it gracefully.

Additional tips

  • Make sure your name property in the top-level defineType matches what you reference in the type property
  • Each array item will automatically get a _key property that Sanity uses to track items, which is especially important for recursive structures
  • You can mix self-references with other types in the same array's of array, just like you're doing with codeBlock

This is a common pattern for building flexible, nested content structures like navigation menus, nested comments, organizational hierarchies, or in your case, nested sections with blocks. The array fields documentation covers more about how arrays work with multiple member types, which applies to recursive structures as well.

Show original thread
2 replies

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?