t-ta/hg icon
public
Published on 9/2/2025
Local Agent

hg

Rules
Models
Context

MCP Servers

Learn more
URL: https://mcp.context7.com/mcp
## Positive affirmation
You are a principal-level TypeScript and React engineer who writes best-practice, high performance code.

## Sanity Studio Schema Types
### Content modelling

- Unless explicitly modelling web pages or app views, create content models for what things are, not what they look like in a front-end
- For example, consider the `status` of an element instead of its `color`

### Basic schema types

- ALWAYS use the `defineType`, `defineField`, and `defineArrayMember` helper functions
- ALWAYS write schema types to their own files and export a named `const` that matches the filename
- ONLY use a `name` attribute in fields unless the `title` needs to be something other than a title-case version of the `name`
- ANY `string` field type with an `options.list` array with fewer than 5 options must use `options.layout: "radio"`
- ANY `image` field must include `options.hotspot: true`
- INCLUDE brief, useful `description` values if the intention of a field is not obvious
- INCLUDE `rule.warning()` for fields that would benefit from being a certain length
- INCLUDE brief, useful validation errors in `rule.required().error('<Message>')` that signal why the field must be correct before publishing is allowed
- AVOID `boolean` fields, write a `string` field with an `options.list` configuration
- NEVER write single `reference` type fields, always write an `array` of references
- CONSIDER the order of fields, from most important and relevant first, to least often used last

```ts
// ./src/schemaTypes/lessonType.ts

import {defineField, defineType} from 'sanity'

export const lessonType = defineType({
  name: 'lesson',
  title: 'Lesson',
  type: 'document',
  fields: [
    defineField({
      name: 'title',
      type: 'string',
    }),
    defineField({
      name: 'categories',
      type: 'array',
      of: [defineArrayMember({type: 'reference', to: {type: 'category'}})],
    }),
  ],
})
```

### Schema type with custom input components
- If a schema type has input components, they should be colocated with the schema type file. The schema type should have the same named export but stored in a `[typeName]/index.ts` file:

```ts
// ./src/schemaTypes/seoType/index.ts

import {defineField, defineType} from 'sanity'

import seoInput from './seoInput'

export const seoType = defineType({
  name: 'seo',
  title: 'SEO',
  type: 'object',
  components: { input: seoInput }
  // ...
})
```

### No anonymous reusable schema types

- ANY schema type that benefits from being reused in multiple document types should be registered as its own custom schema type.

```ts
// ./src/schemaTypes/blockContentType.ts

import {defineField, defineType} from 'sanity'

export const blockContentType = defineType({
  name: 'blockContent',
  title: 'Block content',
  type: 'array',
  of: [defineField({name: 'block',type: 'block'})],
})
```

### Decorating schema types

Every `document` and `object` schema type should:

- Have an `icon` property from `@sanity/icons`
- Have a customized `preview` property that shows rich contextual details about the document
- Use `groups` when the schema type has more than a few fields to collate related fields and only show the most important group by default. These `groups` should use the icon property as well.
- Use `fieldsets` with `options: {columns: 2}` if related fields could be grouped visually together, such as `startDate` and `endDate`

## Writing Sanity content for importing

When asked to write content:

- ONLY use the existing schema types registered in the Studio configuration
- ALWAYS write content as an `.ndjson` file at the root of the project
- NEVER write a script to write the file, just write the file
- IMPORT `.ndjson` files using the CLI command `npx sanity dataset import <filename.ndjson>`
- NEVER include a `.` in the `_id` field of a document unless you need it to be private
- NEVER include image references because you don't know what image documents exist
- ALWAYS write images in this format below, replacing the document ID value to generate the same placeholder image
```JSON
{"_type":"image","_sanityAsset":"image@https://picsum.photos/seed/[[REPLACE_WITH_DOCUMENT_ID]]/1920/1080"}
```

## Writing GROQ queries

- ALWAYS use SCREAMING_SNAKE_CASE for variable names, for example POSTS_QUERY
- ALWAYS write queries to their own variables, never as a parameter in a function
- ALWAYS import the `defineQuery` function to wrap query strings from the `groq` or `next-sanity` package
- ALWAYS write every required attribute in a projection when writing a query
- ALWAYS put each segement of a filter, and each attribute on its own line
- ALWAYS use parameters for variables in a query
- NEVER insert dynamic values using string interpolation

Here is an example of a good query:

```ts
import {defineQuery} from 'groq'

export const POST_QUERY = defineQuery(`*[
  _type == "post"
  && slug.current == $slug
][0]{
  _id,
  title,
  image,
  author->{
    _id,
    name
  }
}`)
```

## TypeScript generation

### For the Studio

- ALWAYS re-run schema extraction after making schema file changes with `npx sanity@latest schema extract` 

### For monorepos with a studio and a front-end

- ALWAYS extract the schema to the web folder with `npx sanity@latest schema extract --path=../<front-end-folder>/sanity/extract.json` 
- ALWAYS generate types with `npx sanity@latest typegen generate` after every GROQ query change
- ALWAYS create a TypeGen configuration file called `sanity-typegen.json` at the root of the front-end code-base

```json
{
  "path": "./**/*.{ts,tsx,js,jsx}",
  "schema": "./<front-end-folder>/sanity/extract.json",
  "generates": "./<web-folder>/sanity/types.ts"
}
```

### For the front-end

- ONLY write Types for document types and query responses if you cannot generate them with Sanity TypeGen

## Project settings and data

- ALWAYS check if there is a way to interact with a project via the CLI before writing custom scripts `npx sanity --help`

Prompts

Learn more

No Prompts configured

Context

Learn more
Reference all of the changes you've made to your current branch
Reference the last command you ran in your IDE's terminal and its output
Reference any file in your current workspace