Skip to content

/sanity-singletons

Configure singleton documents in a Sanity Studio using the document.singletons registry. Use when a developer wants a fixed-id document (settings, navigation, footer) edited in place, hidden from the default content list, with no "create new" or "duplicate" affordances — or when

BOOST
From plugin
sanity
1889 skills4 commands1 MCP
Install
$ npx -y skills add sanity-io/agent-toolkit --skill sanity-singletons --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/sanity-singletons

Context preview

The summary Claude sees to decide when to auto-load this skill.

Configure singleton documents in a Sanity Studio using the document.singletons registry. Use when a developer wants a fixed-id document (settings, navigation, footer) edited in place, hidden from the default content list, with no "create new" or "duplicate" affordances — or when

SKILL.md

sanity-singletons.SKILL.md
name: sanity-singletons
description: Configure singleton documents in a Sanity Studio using the document.singletons registry. Use when a developer wants a fixed-id document (settings, navigation, footer) edited in place, hidden from the default content list, with no "create new" or "duplicate" affordances — or when migrating a userland singleton implementation or a third-party singleton plugin (e.g. sanity-plugin-singleton-management) to the first-class API.

Sanity Singletons

A "singleton" is a document with a fixed id that can be created exactly once. Common examples: site settings, navigation, footer content. Studio supports singletons as a first-class primitive via the `document.singletons` configuration registry plus a small set of Structure Tool helpers.

**Requires `sanity` 6.17.0 or later.** Check the installed version in the lockfile before using this API. On older Studios, either upgrade first or use the userland pattern (fixed `documentId` in a custom structure, plus manual `newDocumentOptions` and `duplicate` filtering) described in `sanity-best-practices` → `studio-structure`.

When to use this skill

  • A developer asks how to create a "settings document" or "singleton".
  • A studio configuration needs a `document.singletons` registry entry.
  • Structure Tool needs to render a singleton as a list item or document pane.
  • You're migrating an existing userland singleton implementation to the first-class API.
  • You're migrating from a third-party singleton plugin such as `sanity-plugin-singleton-management` (or its predecessor `sanity-plugin-singleton-tools`).

Registering a singleton

Singletons are registered in configuration, **not** on the schema type. A singleton definition binds a _definition id_ to a _document id_ and a _schema type_:

import {defineConfig, defineSingleton} from 'sanity'

export default defineConfig({
  schema: {
    types: [/* siteSettings and campaign are ordinary document types */],
  },
  document: {
    singletons: [
      // String shorthand — expands to
      // {id: 'siteSettings', documentId: 'siteSettings', schemaType: 'siteSettings'}
      'siteSettings',

      // Definition object. `defineSingleton` is an optional typed identity
      // helper; a plain object literal works too. `id` is omitted here, so it
      // inherits each `documentId`.
      defineSingleton({
        documentId: 'springCampaign',
        schemaType: 'campaign',
        title: 'Spring campaign', // optional display metadata
        initialValue: {season: 'spring'}, // optional per-singleton initial value
      }),
      defineSingleton({
        documentId: 'summerCampaign',
        schemaType: 'campaign',
        title: 'Summer campaign',
        initialValue: {season: 'summer'},
      }),
    ],
  },
})

Key facts:

  • **`defineSingleton` produces a singleton _definition_, not a document schema.** The schema type it references is defined separately with `defineType` and needs no singleton-specific configuration.
  • **Multiple singletons may share a schema type** (like the two campaigns above), each with its own `title`, `icon`, and `initialValue` (falling back to the schema type's), and a shared schema type may also back ordinary documents.
  • **The definition id is the singleton's stable identity**, and it is **optional** — it inherits `documentId` when omitted. Structure code references it (`S.listItem().singleton('springCampaign')`). Set it explicitly only to be verbose, to guard against future collisions, or to address a singleton universally when different workspaces or environments map it to different document ids.
  • A resolver function is also accepted: `singletons: (prev, context) => [...prev, ...]`. Resolvers only ever receive fully resolved definitions (string shorthands are expanded first).

Validation at config-resolution time (all failures aggregate into one `ConfigResolutionError`):

  • `id`: non-empty, unique across definitions (inherited ids count — an explicit id may not collide with another definition's inherited one). Used verbatim as a Structure Tool node id, so it is limited to `[a-zA-Z0-9._-]` and may not start with `__edit__`. It also may not match the name of a document type that no singleton claims, since the default content list keys both by id (the string shorthand never trips this — the type it names is claimed by the definition itself).
  • `documentId`: non-empty, unique, published-id shaped (no `drafts.` / `versions.` prefix, only `[a-zA-Z0-9._-]`).
  • `schemaType`: must name an existing document type. Need not be unique.
  • Templates: an untagged template must not reuse a definition id (the generated singleton template claims it); at most one template may carry a given `singleton` tag; tags must reference registered definitions.

What Studio does automatically

1. **Generates a dedicated initial value template per singleton** — tagged with the definition id via `ResolvedTemplate.singleton`, value from `definition.initialValue ?? schemaType.initialValue` — instead of the plain per-type template, and **removes tagged templates from every "create new" surface** (global create menu, structure panes, reference inputs). The tagged template stays in `source.templates`, so opening the singleton before it exists still applies its initial value. 2. **Injects `context.singleton`** (the definition id) into document-scoped configuration contexts — `document.actions`, `badges`, `inspectors`, field actions, `comments.enabled`, `askToEdit.enabled` — looked up by _published_ document id, so drafts and release versions of the singleton match, however the document was opened (structure, intent, deep link, search). 3. **Filters the `duplicate` document action**, after all user resolvers run, so it cannot be reintroduced via `document.actions`. 4. **Hides the schema type from the implicit default content list** in Structure Tool, and **appends the singleton itself to that list** — one item per definition, after the document type lists,

Read more
Ships withsanity

Collection of resources to help AI agents build better with Sanity.

Get the whole plugin, auto-invoked

Other skills on sanity.