# Course: Typed content with Sanity TypeGen
https://www.sanity.io/learn/course/typescripted-content

Learn how to generate TypeScript types from a Sanity Studio schema and GROQ queries. Ensure robust, maintainable, and error-resistant code, equipping you with advanced techniques for content schema management and type-safe data fetching.

---

## Navigation

## Contents

1. [Introduction](https://www.sanity.io/learn/course/typescripted-content/introduction) · [markdown](https://www.sanity.io/learn/course/typescripted-content/introduction.md)
2. [Extracting your schema](https://www.sanity.io/learn/course/typescripted-content/extracting-your-schema) · [markdown](https://www.sanity.io/learn/course/typescripted-content/extracting-your-schema.md)
3. [Generating types from your schema](https://www.sanity.io/learn/course/typescripted-content/generating-types-from-your-schema) · [markdown](https://www.sanity.io/learn/course/typescripted-content/generating-types-from-your-schema.md)
4. [Configuring Sanity TypeGen for multiple-folder projects](https://www.sanity.io/learn/course/typescripted-content/configuring-sanity-typegen-for-multiple-folder-projects) · [markdown](https://www.sanity.io/learn/course/typescripted-content/configuring-sanity-typegen-for-multiple-folder-projects.md)
5. [Generating types for GROQ query results](https://www.sanity.io/learn/course/typescripted-content/generating-type-for-groq-query-results) · [markdown](https://www.sanity.io/learn/course/typescripted-content/generating-type-for-groq-query-results.md)

---

## Lesson 1: Introduction
https://www.sanity.io/learn/course/typescripted-content/introduction

Learn how to use Sanity TypeGen to automatically generate TypeScript type definitions for documents in Sanity Content Lake and for the result of GROQ queries in your front ends and web applications.

> [!NOTE]
> This course covers the same TypeGen concepts as the [Generating types](https://www.sanity.io/learn/course/day-one-with-sanity-studio/generating-types) lesson in the Day One course, but in more depth and with a different project structure. If you've already completed that lesson, this course will deepen your understanding.



This course teaches you to generate TypeScript types from a Sanity Studio schema and GROQ queries. Starting with extracting a static schema representation, the course guides through generating types for Sanity Studio schemas and front-end GROQ queries. This skill set streamlines the development process and enriches your toolkit with advanced practices in managing content schemas and data fetching with type safety in mind.



In this course, you will learn the following:



- How to extract a static representation of your Sanity Studio schema

- How to generate TypeScript types from that static representation

- How to generate TypeScript types from GROQ queries in a front end project

- How to use these types in front end code

- Configure automatic type generation for seamless development workflow

> [!NOTE]
> Sanity TypeGen is now generally available! This course has been updated to reflect the GA release. For a complete overview of what changed, see the [TypeGen GA announcement](https://www.sanity.io/blog/sanity-typegen-ga) and [migration guide](https://www.sanity.io/learn/lesson/migrating-from-typegen-beta-to-ga).



## Prerequisites



You should be able to follow this course if you have completed [Day one content operations](https://www.sanity.io/learn/course/day-one-with-sanity-studio) course. 



> [!TIP]
> Complete [Day one content operations](https://www.sanity.io/learn/course/day-one-with-sanity-studio)



This course also assumes basic knowledge of TypeScript and will not go into detail on how TypeScript works or explain the syntax. That being said, all the steps are shown to you in code, thus you can use this course as an introduction to TypeScript. 



If you want to learn or dive deeper into TypeScript, we recommend these resources:



- [Total TypeScript](https://www.totaltypescript.com/) by Matt Pocock

- [TypeScript on Egghead](https://egghead.io/q/typescript)

- [TypeScript on FreeCodeCamp](https://www.freecodecamp.org/news/tag/typescript/)


Sanity TypeGen is now generally available (GA) as of Sanity Studio v5, marking it as production-ready with stable APIs. Make sure you have the latest version of the `sanity` package installed to take advantage of all the GA features.



Upgrade the `sanity` dependency in the Studio folder:



```sh:Terminal
npm install sanity@latest
```

## A note on project structure



This course uses the code at the completion of the Day One with Sanity Studio course – where your Studio and front-end are in two separate folders, not connected as a "monorepo"



```
/
├── day-one-with-sanity-nextjs
│   ├── README.md
│   ├── next-env.d.ts
│   ├── next.config.ts
│   ├── package.json
│   ├── postcss.config.js
│   ├── public
│   ├── src
│   ├── tailwind.config.ts
│   └── tsconfig.json
└── day-one-with-sanity
    ├── README.md
    ├── dist
    ├── package.json
    ├── sanity.cli.ts
    ├── sanity.config.ts
    ├── schemaTypes
    ├── static
    ├── structure
    └── tsconfig.json
```

- [ ] Open the [Day one content operations](https://www.sanity.io/learn/course/day-one-with-sanity-studio) source code in a code editor and a terminal


There are other ways of structuring the Studio and front end(s) relative to each other, which can impact your work with TypeScript code generation. If you want to explore these, head to the [Sanity TypeGen docs](https://www.sanity.io/learn/docs/apis-and-sdks/sanity-typegen).



Let's dive in!



---

## Lesson 2: Extracting your schema
https://www.sanity.io/learn/course/typescripted-content/extracting-your-schema

Learn how to extract your Sanity Studio schema into a JSON file. This is a crucial step before generating TypeScript types. This file, a static representation of your data's shape, will be used for type generation.

Before generating TypeScript types for the frontend, you need to extract the Sanity Studio schema written in JavaScript into a *static representation*, a JSON file describing the shape of the data your Sanity Studio produces.



- **Run** the following Sanity CLI command in your studio project folder:


```sh:Terminal
npx sanity schema extract
```

If your command ran successfully, you should see a new file called `schema.json` in your Studio project folder. In this course, you will only use this file for the type generation; you don't need to do anything else with it.



## Automatic schema extraction



While the manual command above is useful for understanding the extraction process, TypeGen can also extract your schema automatically for Studio projects. When you enable automatic extraction through configuration, the `schema.json` file updates automatically whenever you run `sanity dev` or `sanity build`.



Manual extraction remains useful for understanding what's happening under the hood and is especially important for monorepo setups where your Studio and frontend application are in separate packages. In those cases, the `schema.json` file serves as the bridge between your Studio schema and your frontend types.



We'll cover how to configure automatic schema extraction in a later lesson. For now, the manual command gives you a clear view of the extraction process.



If you explore its content, you will find your Studio schema described in a JSON format. For example, the document type for `venue` will look something like this:



```json:schema.json
{
  "name": "venue",
  "type": "document",
  "attributes": {
    "_id": {
      "type": "objectAttribute",
      "value": {
        "type": "string"
      }
    },
    "_type": {
      "type": "objectAttribute",
      "value": {
        "type": "string",
        "value": "venue"
      }
    },
    "_createdAt": {
      "type": "objectAttribute",
      "value": {
        "type": "string"
      }
    },
    "_updatedAt": {
      "type": "objectAttribute",
      "value": {
        "type": "string"
      }
    },
    "_rev": {
      "type": "objectAttribute",
      "value": {
        "type": "string"
      }
    },
    "name": {
      "type": "objectAttribute",
      "value": {
        "type": "string"
      },
      "optional": true
    },
    "city": {
      "type": "objectAttribute",
      "value": {
        "type": "string"
      },
      "optional": true
    },
    "country": {
      "type": "objectAttribute",
      "value": {
        "type": "string"
      },
      "optional": true
    }
  }
}
```

This file can be used to develop tooling that needs to know about a Sanity Studio schema. But in this course, you will use it to generate TypeScript types.



---

## Lesson 3: Generating types from your schema
https://www.sanity.io/learn/course/typescripted-content/generating-types-from-your-schema

Learn how to generate TypeScript types from your Sanity Studio schema using the Sanity CLI. This process will create a 'sanity.types.ts' file, providing you with types for all your schema, including built-in and plugin-related types.

You can now generate TypeScript types for your Sanity Studio schema. These types can be helpful in the Studio project, like customizations and contexts where you pass data that corresponds directly to the Studio schema types.



- [ ] **Run** the following Sanity CLI command in your studio project folder:


```sh:Terminal
npx sanity@latest typegen generate
```

When successfully completed, this command creates a `sanity.types.ts` file containing TypeScript types for all your Sanity Studio schema types. Open it to find types for “built-in” schema types. If you have plugins with schema types, those will also be generated.



> [!NOTE]
> Schema Types are especially useful for type safety when creating or patching documents in custom scripts or functions.



```typescript
import type { Event } from './sanity.types.ts'

await client.create<Event>({
  _type: "event",
  _id: uuid(),
  // ... and other fields
})
```

While these types can come in handy in your Studio project, using them in your front end application is extremely useful to improve your development experience.



In the next chapter, you'll learn how to generate types for your front end project.



---

## Lesson 4: Configuring Sanity TypeGen for multiple-folder projects
https://www.sanity.io/learn/course/typescripted-content/configuring-sanity-typegen-for-multiple-folder-projects

Configure Sanity TypeGen to place its generated files in the right locations. Run the typegen command and interpret its results.

Before you can generate types for GROQ query results, you must add some configuration that tells the TypeGen tooling where to look for those queries and where to put the file with the generated types.



Before diving in, it’s important to remember that you are still dependent on the `schema.json` file to generate types for your front end. You should also keep in mind that every time you change the Studio’s schema, you will have to rerun the extraction, and every time you change a GROQ query, you should update your types as well.



- [ ] **Add** typegen configuration to your `sanity.cli.ts` file in your Studio folder. You'll also need `schemaExtraction.enabled: true` to generate the `schema.json` file that typegen uses.


```typescript:sanity.cli.ts
import {defineCliConfig} from 'sanity/cli'

export default defineCliConfig({
  api: {
    projectId: 'your-project-id',
    dataset: 'production'
  },
  schemaExtraction: {
    enabled: true,
  },
  typegen: {
    path: '../day-one-with-sanity-nextjs/src/**/*.{ts,tsx,js,jsx}',
    schema: 'schema.json',
    generates: '../day-one-with-sanity-nextjs/src/sanity/types.ts'
  }
})
```

All TypeGen configuration lives in `sanity.cli.ts`. If you have an older project with a separate `sanity-typegen.json` file, move that configuration here — the JSON file is deprecated.



The configuration works like this:



- `path` configures where and which files Sanity TypeGen looks for GROQ queries. In this case, it will look through all the files in the front end’s `src` folder

- `schema` is where to find the static schema representation. The default value is `schema.json`.

- `generates` sets the path and the file name with the generated TypeScript definitions, in this case, in the front end’s `sanity` folder

> [!TIP]
> `schemaExtraction.enabled: true` generates the `schema.json` file automatically during `sanity dev` and `sanity build`. If you also want to generate types in the studio itself (for custom components, etc.), add `typegen.enabled: true` as well. This is covered in the [Generating types](https://www.sanity.io/learn/course/day-one-with-sanity-studio/generating-types) lesson.



With this configuration file in place, you can now run the `typegen` command:



- [ ] **Run** the command from your Studio folder in your terminal


```sh:Terminal
npx sanity typegen generate
```

If run successfully, you’ll see the result like this:



```sh:Terminal
✔ Generated TypeScript types for 14 schema types and 0 GROQ queries in 0 files into: ../day-one-with-sanity-nextjs/src/sanity/types.ts
```

- [ ] Open the `types.ts` file in your Next.js project folder and inspect its content


Notice how it says “0 GROQ queries,” this means you have to tweak your front end code to let Sanity TypeGen find your queries as well.



---

## Lesson 5: Generating types for GROQ query results
https://www.sanity.io/learn/course/typescripted-content/generating-type-for-groq-query-results

Make your queries discoverable. Generate TypeScript types for your GROQ queries.

With the TypeGen configuration set up to look for GROQ queries in your front end project, the last step is to make those queries discoverable for the tooling.



First, go into your front end folder. If you follow this course with the code from the Day One course, you can search for `EVENTS_QUERY` to find the index route file.



```typescript:./src/app/page.tsx
const EVENTS_QUERY = `*[_type == "event" && defined(slug.current)]{_id, name, slug, date}|order(date desc)`;
```

To get types for GROQ query results from TypeGen, you need to make sure of the following:



- The string with the query is assigned to a variable

- The variable name needs to be globally unique since it’s used for the type name

- The string needs to be a syntactically valid GROQ query (for example, you should be able to run it successfully in the Vision plugin or on [groq.dev](https://groq.dev))

- The string with the query needs to be prefixed with the `groq` [template literal](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) or the `defineQuery` helper function

> [!NOTE]
> Prefer the `defineQuery` function over `groq`, as it also unlocks automatic type inference when using Sanity Client



The `EVENTS_QUERY` is only missing the last point to be picked up by the TypeGen command.



If you’re using Next.js, you can import `groq` and `defineQuery` from the `next-sanity` package.



For other frameworks, you can install the `groq` package:



```sh:Terminal
npm i groq
```

Add the `defineQuery` function like this; remember to save the file after:



```typescript
import { defineQuery } from 'next-sanity'
// import { defineQuery } from 'groq' // in other frameworks

const EVENTS_QUERY = defineQuery(`*[_type == "event" && defined(slug.current)]{_id, name, slug, date}|order(date desc)`)
```

- [ ] Import `defineQuery` into the route file with the `EVENTS_QUERY` variable

- [ ] Add the `defineQuery` template literal to your GROQ query string


Both the `groq` template literal and `defineQuery` function will add syntax highlighting to VS Code when you have the [Sanity extension installed](https://marketplace.visualstudio.com/items?itemName=sanity-io.vscode-sanity). It’s also used by the TypeGen tooling to identify something as a GROQ query.



Return to the Studio folders and run the `npx sanity typegen generate` command again. It should pick up the GROQ query, and the output should be like this:



```:Terminal
✔ Generated TypeScript types for 14 schema types and 1 GROQ queries in 1 files into: ../day-one-with-sanity-nextjs/src/sanity/types.ts
```

- [ ] Generate your types again to create types for GROQ queries


Open your `types.ts` file in your front end folder, and search for `EVENTS_QUERY` to find your new type:



```typescript:./src/sanity/types.ts
// Source: ../frontend/src/app/page.tsx
// Variable: EVENTS_QUERY
// Query: *[_type == "event" && defined(slug.current)]{_id, name, slug, date}|order(date desc)
export type EVENTS_QUERY_RESULT = Array<{
  _id: string;
  name: string | null;
  slug: Slug | null;
  date: string | null;
}>;
```

- [ ] Find the `EVENTS_QUERY_RESULT` type in `types.ts`


## Working with generated types: Utilities for real-world schemas



Now that you have generated types for your schema and GROQ queries, TypeGen provides powerful utilities to work with these types in real-world scenarios. Two utilities in particular, `Get` and `FilterByType`, make it much easier to extract and work with nested types from your Sanity documents.



### The `Get` utility



The `Get` utility extracts deeply nested properties from your types—up to 20 levels deep—without complex TypeScript gymnastics. This is especially useful when working with nested objects, references, or array items in your schema.



Instead of writing verbose type expressions with multiple `NonNullable` wrappers, you can use a simple path syntax:



```typescript
import type { Get } from 'sanity'
import type { Event } from './sanity/types'

// Extract a deeply nested type
type VenueCity = Get<Event, 'venue.city'>

// Works with arrays too
type FirstImageAlt = Get<Event, 'images[0].alt'>

// Compare to the old way:
type OldWay = NonNullable<NonNullable<Event['venue']>['city']>
```

The `Get` utility handles nullable types automatically and provides a clean, readable syntax that mirrors how you'd access the property in JavaScript.



### The `FilterByType` utility



The `FilterByType` utility filters specific types from unions using the `_type` discriminator. This is particularly useful when working with Portable Text or modular content arrays where you have a union of different block types.



For example, if you have a page builder field that can contain multiple block types, you can easily extract just the types you need:



```typescript
import type { FilterByType } from 'sanity'
import type { PageBuilder } from './sanity/types'

// Extract only hero blocks from a union of block types
type HeroBlock = FilterByType<PageBuilder, 'hero'>

// Works with multiple types too
type ContentBlocks = FilterByType<PageBuilder, 'hero' | 'textBlock' | 'imageGallery'>
```

This makes it easy to create type-safe component props or helper functions that work with specific block types from your modular content.



Thanks to automatic type inference, this type should be automatically applied when using Sanity Client's fetch.



```typescript
const events = await client.fetch(EVENTS_QUERY);
      // ^ typed as EVENTS_QUERY_RESULT
```

Using these GROQ query result types with Sanity Client is covered in the [Display content in Next.js](https://www.sanity.io/learn/course/day-one-with-sanity-studio/bringing-content-to-a-next-js-front-end) lesson of the [Day one content operations](https://www.sanity.io/learn/course/day-one-with-sanity-studio) course, which you should have already completed.



---

## Related Resources

- [All courses and lessons](https://www.sanity.io/learn/sitemap.md)
- [Complete content for LLMs](https://www.sanity.io/learn/llms-full.txt)
