---
url: /strapi-typed-client/reference/generated-types.md
---
# Generated Types

This page explains the structure of the TypeScript files produced by the `strapi-types generate` command and the type categories they contain.

## Output Files

Generated files are written to the directory you pass with the required `--output` flag — a directory in your source tree that you commit, e.g. `./src/strapi`. The default `--format js` emits compiled `.js` + `.d.ts`; `--format ts` emits raw `.ts` instead.

| File                                | Description                                                                                             |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------- |
| `types.d.ts`                        | All TypeScript interfaces: base types, input types, payload types, components, filters, populate params |
| `client.js`                         | The `StrapiClient` class with typed methods for every content type (also exports `SCHEMA_HASH`)         |
| `client.d.ts`                       | Type declarations for the client                                                                        |
| `index.js`                          | Re-exports everything from `types` and `client`                                                         |
| `index.d.ts`                        | Type declarations for the index                                                                         |
| `validation.js` / `validation.d.ts` | Zod schemas for every create/update input — only with `--validation zod`, not re-exported from `index`  |

```
src/strapi/
  types.d.ts        # Type definitions
  client.js         # Runtime client code + SCHEMA_HASH constant
  client.d.ts       # Client type declarations
  index.js          # Re-export barrel
  index.d.ts        # Index type declarations
  validation.js     # Zod validators (only with --validation zod)
  validation.d.ts
```

## Split types

On a large schema `types` grows to thousands of lines. Pass `--split-types` (or `splitTypes: true` in [`withStrapiTypes`](/guide/nextjs)) to spread it over one file per content type and one per component category:

```
src/strapi/
  types.ts                      # barrel: re-exports everything below
  base.ts                       # shared primitives, filter operators, query helpers
  collections/
    _internal.ts                # helpers the files share; not re-exported from `types`
    article.ts                  # Article, ArticleCreateInput, ArticleFilters, ArticlePopulateParam, ArticleGetPayload, ...
    category.ts
    components/
      shared.ts                 # components of the `shared` category
  client.ts
  index.ts
```

`types` stays a barrel, so `import { Article } from './strapi/types'` and `from './strapi'` keep working; import from `collections/article` directly if you want the language server to load only that file. Later runs keep the layout, `--single-file` goes back, and files of removed collections are deleted (only files carrying the generated header — your own files are left alone). Unchanged files are not rewritten, so a schema change touches only the files it affects and diffs and CODEOWNERS rules can follow collections.

## Type Categories

The generator produces three categories of types for each content type, plus supporting utility types.

### 1. Base Types

Base types represent the shape of data **returned by Strapi** for read operations (without populate). They contain only scalar fields and the standard base fields.

```ts
export interface Article {
    readonly __typename?: 'Article'
    id: number
    documentId: string
    createdAt: string
    updatedAt: string
    title: string
    slug: string
    body: string | null
    publishDate: string | null
    views: number
    status: 'draft' | 'published' | 'archived'
}
```

Key characteristics:

* Includes `id`, `documentId`, `createdAt`, `updatedAt` on every type.
* Scalar fields only -- relations, media, components, and dynamic zones are **not** present.
* Non-required fields have `| null`.
* Enumerations become union literal types.
* A readonly `__typename` field provides nominal typing to distinguish structurally similar interfaces.

### 2. Input Types

Input types are used for `create` and `update` operations: `ArticleCreateInput` enforces what Strapi requires on create, `ArticleUpdateInput` makes every key optional for partial updates.

```ts
export interface ArticleCreateInput {
    title: string // required in the schema
    slug?: string | null
    status?: 'draft' | 'published' | 'archived' | null
    views?: string | number | null // biginteger
    category?: RelationInput<'manyToOne'> // one id or reference, at most one in a list, or { connect | disconnect | set }
    cover?: MediaInput // media -> ID
    gallery?: MultiMediaInput // multiple media -> ID array
    seo?: SeoCreateInput | null // single component
    sections?: SectionCreateInput[] // repeatable component — never null
    blocks?: (HeroDzCreateInput | CtaDzCreateInput)[] // dynamic zone — never null
    locale?: string
    publishedAt?: string | null
}
```

The full rules — required fields with defaults, required components, private and password fields — are in [Input Types](/guide/input-types#create-vs-update).

### 3. Payload Types (GetPayload)

Payload types use TypeScript generics to resolve the return type based on your `populate` parameter. This is what enables type-safe populate inference.

```ts
export type ArticleGetPayload<P extends { populate?: any } = {}> = Article &
    (P extends { populate: infer Pop }
        ? Pop extends '*' | true
            ? {
                  category?: Category | null
                  cover?: MediaFile
                  tags?: Tag[]
                  blocks?: (Hero | Cta)[]
              }
            : Pop extends readonly (infer _)[]
              ? {
                    category?: 'category' extends Pop[number]
                        ? Category | null
                        : never
                    cover?: 'cover' extends Pop[number] ? MediaFile : never
                    // ...
                }
              : {
                    category?: 'category' extends keyof Pop
                        ? /* nested resolve */ Category | null
                        : never
                    // ...
                }
        : {})
```

The payload type handles three populate styles:

| Populate Style | Example                                                    | Behavior                              |
| -------------- | ---------------------------------------------------------- | ------------------------------------- |
| Wildcard       | `populate: '*'` or `populate: true`                        | All populatable fields included       |
| Array          | `populate: ['category', 'cover']`                          | Only named fields included            |
| Object         | `populate: { category: true, cover: { fields: ['url'] } }` | Per-field control with nested options |

::: tip
You rarely need to use `GetPayload` directly. The `StrapiClient` methods automatically infer the correct return type from your `populate` parameter.
:::

## Component Types

Components are generated as separate interfaces, mirroring their Strapi structure.

```ts
export interface SeoComponent {
    id: number
    metaTitle: string
    metaDescription: string | null
    shareImage: MediaFile | null
}

export interface SeoComponentInput {
    id?: number
    metaTitle?: string | null
    metaDescription?: string | null
    shareImage?: number | null
}
```

Component types follow the same base/input split as content types. The `id` field is included (components have IDs in Strapi) but `documentId` is not (components are not standalone documents).

## PopulateParam Types

For each content type and component that has populatable fields, a `PopulateParam` type is generated. This provides autocomplete and type safety for the `populate` parameter.

```ts
export type ArticlePopulateParam = {
    category?:
        | true
        | { count: true; filters?: CategoryFilters } // { count: number } in the result
        | {
              count?: false
              fields?: (keyof Category & string)[]
              populate?:
                  | CategoryPopulateParam
                  | (keyof CategoryPopulateParam & string)[]
                  | '*'
              filters?: CategoryFilters
              sort?: SortValue<Category> | SortValue<Category>[]
              limit?: number
              start?: number
          }
    cover?: true | { fields?: (keyof MediaFile & string)[] }
    tags?:
        | true
        | {
              fields?: (keyof Tag & string)[]
              filters?: TagFilters
              sort?: SortValue<Tag> | SortValue<Tag>[]
              limit?: number
              start?: number
          }
    blocks?:
        | true
        | {
              on?: {
                  'shared.hero'?: true | { fields?: (keyof Hero & string)[] }
                  'shared.cta'?: true | { fields?: (keyof Cta & string)[] }
              }
          }
}
```

Populate params support:

* `true` for simple population.
* Object syntax with `fields`, `filters`, `sort`, `limit`, `start` for fine-grained control.
* `{ count: true }` on relations (optionally with `filters`) to get `{ count: number }` instead of the records — see [Counting Relations](/guide/populate#counting-relations).
* Nested `populate` for deep population chains.
* Dynamic zone `on` syntax for component-specific options.

## Filter Types

Each content type gets a typed filter interface:

```ts
export interface ArticleFilters extends LogicalOperators<ArticleFilters> {
    id?: number | IdFilterOperators
    documentId?: string | StringFilterOperators
    createdAt?: string | DateFilterOperators
    updatedAt?: string | DateFilterOperators
    publishedAt?: string | DateFilterOperators
    title?: string | StringFilterOperators
    views?: number | NumberFilterOperators
    status?: ('draft' | 'published' | 'archived') | StringFilterOperators
    category?: {
        id?: number | IdFilterOperators
        documentId?: string | StringFilterOperators
        [key: string]: any
    }
    seo?: SharedSeoFilters
}
```

Every component also gets its own filter interface, referenced by the entities that use it. Component filters carry a numeric `id` but no `documentId` or timestamps, and they nest recursively:

```ts
export interface SharedSeoFilters extends LogicalOperators<SharedSeoFilters> {
    id?: number | IdFilterOperators
    metaTitle?: string | StringFilterOperators
    openGraph?: SharedOpenGraphFilters
}
```

Dynamic zone fields get no filter key — Strapi cannot filter polymorphic structures, so the type reflects what the REST API actually accepts.

Filter utility types are also generated:

| Type                     | Used For                                |
| ------------------------ | --------------------------------------- |
| `StringFilterOperators`  | `$eq`, `$contains`, `$startsWith`, etc. |
| `NumberFilterOperators`  | `$eq`, `$lt`, `$gt`, `$between`, etc.   |
| `BooleanFilterOperators` | `$eq`, `$ne`, `$null`                   |
| `DateFilterOperators`    | `$eq`, `$lt`, `$gt`, `$between`, etc.   |
| `IdFilterOperators`      | `$eq`, `$ne`, `$in`, `$notIn`           |
| `LogicalOperators<T>`    | `$and`, `$or`, `$not`                   |

## Internal Utility Types

The following types are generated for internal use by the client and payload resolution. You generally do not need to reference them directly:

| Type                                  | Purpose                                              |
| ------------------------------------- | ---------------------------------------------------- |
| `_EntityField<T>`                     | Extracts field names excluding `__typename`          |
| `_SortValue<T>`                       | Sort string like `'title'` or `'title:desc'`         |
| `_ApplyFields<TFull, TBase, TEntry>`  | Narrows type based on `fields` selection in populate |
| `Equal<X, Y>`                         | Exact type equality check                            |
| `GetPopulated<TBase, TPopulate>`      | Maps base type to its `GetPayload` variant           |
| `SelectFields<TFull, TBase, TFields>` | Picks specific fields from the type                  |

## TypeMap Generation

The generated `StrapiClient` uses an internal `GetPopulated` conditional type that maps each base type to its `GetPayload` variant. This is what enables the client methods to automatically return the correct type based on the `populate` parameter you pass:

```ts
type GetPopulated<TBase, TPopulate> =
    Equal<TBase, Article> extends true
        ? ArticleGetPayload<{ populate: TPopulate }>
        : Equal<TBase, Category> extends true
          ? CategoryGetPayload<{ populate: TPopulate }>
          : // ... one branch per content type
            TBase
```

::: info
The `Equal` type uses exact equality instead of `extends` to prevent TypeScript structural typing from incorrectly matching similar types.
:::
