All skills
sanity-io avatar

/sanity-best-practices

@fc8116b official
by Sanitysanity-io/agent-toolkit187 stars
30

Sanity development best practices for schema design, GROQ queries, TypeGen, Visual Editing, images, Portable Text, Studio structure, localization, migrations, Sanity Functions, webhooks, Blueprints, and framework integrations such as Next.js, Nuxt, Astro, Remix, SvelteKit, Angular, Hydrogen, and the App SDK. Use this skill whenever working with Sanity schemas, defineType or defineField, GROQ or defineQuery, content modeling, Presentation or preview setups, Sanity-powered frontend integrations, event-driven content automation, documentEventHandler, defineDocumentFunction, defineMediaLibraryAssetFunction, @sanity/functions, @sanity/blueprints, sanity.blueprint.ts, event-driven content automation, or when reviewing and fixing a Sanity codebase.

Use this Skill: https://skilld.dev/gh/sanity-io/agent-toolkit/sanity-best-practices

This session only. Nothing lands on disk.

referencestypegen.md

≈1.6k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Sanity TypeGen Rules

1. The Workflow

Sanity TypeGen generates TypeScript types from your schema and GROQ queries. Types can be generated automatically or manually.

Automatic (Recommended)

Enable in sanity.cli.ts — types regenerate during sanity dev and sanity build:

// sanity.cli.ts
import { defineCliConfig } from 'sanity/cli'

export default defineCliConfig({
  typegen: {
    enabled: true,
  },
})

Manual

Run the extract + generate cycle whenever schema or queries change:

  1. Extract: Converts your Schema (TS/JS) into a static JSON representation.
  2. Generate: Scans your codebase for GROQ queries and generates TypeScript types.
npx sanity schemas extract --force && npx sanity typegen generate

Watch Mode (for separate frontends)

If your frontend is in a separate repo from the Studio, use watch mode:

npx sanity typegen generate --watch

2. The "Update Types" Pattern

For manual workflows, implement a single script:

package.json:

"scripts": {
  "typegen": "sanity schemas extract --force && sanity typegen generate"
}

Git Strategy for Generated Files

Option A: Commit generated types (Recommended for most teams)

  • Types available immediately after git pull
  • CI/CD doesn't need to run typegen
  • Can cause merge conflicts

Option B: Generate in CI (Recommended for larger teams) Add to .gitignore:

# Sanity TypeGen (generated)
sanity.types.ts
schema.json

Then ensure CI runs typegen before build:

# Example GitHub Actions
- run: npm run typegen
- run: npm run build

3. Configuration (sanity.cli.ts)

Note: sanity-typegen.json is deprecated. Move your configuration to sanity.cli.ts.

// sanity.cli.ts
import { defineCliConfig } from 'sanity/cli'

export default defineCliConfig({
  typegen: {
    enabled: true, // Auto-generate during sanity dev/build
    path: "./src/**/*.{ts,tsx,js,jsx,astro,svelte,vue}", // Glob to find queries
    schema: "schema.json", // Schema file from extract
    generates: "./sanity.types.ts", // Output file
    overloadClientMethods: true, // Auto-type client.fetch() calls
  },
})

Project Structure Examples

Monorepo (recommended) (Studio in studio/, Frontend in web/ — same config works under apps/):

export default defineCliConfig({
  typegen: {
    path: "../web/src/**/*.{ts,tsx,js,jsx}",
    schema: "schema.json",
    generates: "../web/sanity.types.ts",
  },
})

Single Repo / Embedded Studio (legacy): Use defaults — no extra config needed.

Separate Repos: Use --watch mode in your frontend: sanity typegen generate --watch

4. Usage in Code

Automatic Type Inference (Recommended)

With overloadClientMethods: true (default), client.fetch() automatically returns typed results when you use defineQuery:

import { defineQuery } from "groq";
import { createClient } from "@sanity/client";

const client = createClient({...});

const POSTS_QUERY = defineQuery(`*[_type == "post"]{ title, slug }`);

// Return type is automatically inferred — no manual type import needed!
const posts = await client.fetch(POSTS_QUERY);

Manual Type Import (Alternative)

You can also import generated types directly:

import { defineQuery } from "groq";
// Next.js re-exports defineQuery for convenience:
// import { defineQuery } from "next-sanity";

const AUTHOR_QUERY = defineQuery(`*[_type == "author" && slug.current == $slug][0]{ name, bio }`);

import type { AUTHOR_QUERY_RESULT } from "@/sanity.types";

export default function Author({ data }: { data: AUTHOR_QUERY_RESULT }) {
  return <h1>{data.name}</h1>
}

Required Fields

Use --enforce-required-fields during extraction to translate validation: rule => rule.required() into non-optional types:

npx sanity schemas extract --force --enforce-required-fields
npx sanity typegen generate

Warning: If you use draft previews, fields may still be undefined even with required validation, since drafts can be in an invalid state.

Type Utilities

TypeGen provides utilities for working with complex types:

import type { Get, FilterByType } from 'sanity'
import type { Page, PageBuilder } from './sanity.types'

// Extract deeply nested type (up to 20 levels)
type HeroSection = Get<Page, 'sections', number, 'hero'>

// Filter specific types from unions using _type discriminator
type HeroBlock = FilterByType<PageBuilder, 'hero'>

Unique Query Names

All queries must have unique variable names. Duplicate names across files will cause TypeGen to silently overwrite types. Use descriptive, scoped names:

// Unique names
const POSTS_INDEX_QUERY = defineQuery(`*[_type == "post"]{ title }`)
const POST_DETAIL_QUERY = defineQuery(`*[_type == "post" && slug.current == $slug][0]`)

// Duplicate names will conflict
const QUERY = defineQuery(`*[_type == "post"]`)  // file-a.ts
const QUERY = defineQuery(`*[_type == "author"]`) // file-b.ts — overwrites!

Supported Query Formats

Queries must be assigned to a variable using groq or defineQuery:

// Works — groq template tag
const query = groq`*[_type == "post"]`

// Works — defineQuery
const query = defineQuery(`*[_type == "post"]`)

// Won't work — inline query
await client.fetch(groq`*[_type == "post"]`)

Supported File Types

TypeGen parses queries from: .ts, .tsx, .js, .jsx, .astro, .svelte, .vue

tsconfig Requirements

Ensure sanity.types.ts is included in your tsconfig.json's include array. If your config restricts includes (e.g., ["src/**/*"]) and the types file is at the project root, TypeScript won't pick up the generated types:

{
  "include": ["src/**/*", "sanity.types.ts"]
}

Skipping Individual Queries

Add @sanity-typegen-ignore in a comment before a query to skip type generation:

// @sanity-typegen-ignore
const debugQuery = groq`*[_type == "debug"]`

Source: SKILL.md on GitHub

2 warnings14d5 checks · Risk SAFE
  • Gen Agent Trust Hub14d

    This skill provides comprehensive Sanity.io development best practices, covering schema design, GROQ queries, and integration with major frontend frameworks. It promotes secure development habits, such as proper management of API tokens and environment variables.

  • Socket14d

    1 alert: gptAnomaly

  • Snyk14d

    Risk: LOW · No issues

  • Runlayer6mo

    8/24 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at fc8116b. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 weeks ago.

Activeupdated 2 months ago
  • Next.js
  • Nuxt
  • sanity
  • groq
  • schema
  • typegen
  • portable-text
  • visual-editing
  • astro
  • remix
  • sveltekit
  • migrations
  • localization
  • cms

README badge

README badge for sanity-io/agent-toolkit/sanity-best-practices

Provides guidelines and reference materials for Sanity schema design, GROQ queries, TypeGen, Visual Editing, Portable Text, Studio structure, localization, migrations, Sanity Functions, and framework integrations including Next.js, Nuxt, Astro, Remix, SvelteKit, Angular, and Hydrogen. Use this skill when setting up Sanity projects, designing content models, writing queries, implementing live preview, or integrating Sanity with a frontend framework.

Generated from the current SKILL.md.

Does this skill cover framework integrations like Next.js, Nuxt, and Astro?
Yes. The skill includes integration guides for Next.js, Nuxt, Astro, Remix, SvelteKit, Angular, Hydrogen, and standalone Studio patterns.
What does this skill cover for GROQ queries?
The skill provides GROQ query patterns, type safety approaches, and performance optimization guidelines, with reference materials for detailed examples.
Does this skill include guidance on Sanity Functions and event automation?
Yes. The skill covers Sanity Functions for automating content workflows, including documentEventHandler and defineDocumentFunction patterns.
Can I use this skill for schema design and content modeling?
Yes. The skill provides schema design best practices, field definitions, validation patterns, and content modeling guidance for different use cases.
Does this cover Visual Editing and live preview setup?
Yes. The skill includes guidance on the Presentation Tool, Stega, overlays, and live preview configuration for frontend frameworks.

Generated from the current SKILL.md. These answers refresh after source changes.