> From the [Strife developer docs](https://strife.app/docs/reference/cli/typegen). Every page is listed in [llms.txt](https://strife.app/docs/llms.txt).

# Typegen

Generate TypeScript types from your defineType schemas, and keep them in sync with a CI check.

`strife typegen` turns your [schema definitions](https://strife.app/docs/reference/cli/schemas.md) into TypeScript types matching what the content API actually returns — useful whether or not the rest of your project uses TypeScript. Both subcommands are fully offline: no network request, no authentication, no linked project required. They only need a `strife.config.ts` and your schema files.

## `strife typegen generate`

```sh
npx strife typegen generate [--config <path>] [-o | --output <path>]
```

Reads your schema files and writes TypeScript interfaces to `.strife/types.ts` (override the path with `-o`/`--output`):

```ts
// AUTO-GENERATED by `strife typegen generate` — do not edit by hand.

import type { Content } from '@strifeapp/types';

export interface Articles extends Content {
  heading: string | null;
  body: string;
}
```

The generated shape is the **read** shape — what you get back after fetching a document, not the raw stored form. Two things follow from that:

* Localized fields (`localizable: true`) collapse to the active locale as `T | null` (`null` if that locale hasn't been translated yet). Non-localized fields are plain, non-nullable types.
* `reference`, `references`, `chapters`, and `contentTemplate` fields resolve to the _target_ type's own generated interface, not a raw identifier — a `reference` to your `Author` type produces `author: Author[]` rather than an opaque reference object.
* `displayName` on `Content` is always a `string`, also on a type with `baseProperties: { displayName: { localizable: true } }` — the content index resolves it to the requested locale, falling back to the default locale's name. `baseProperties` changes nothing in the generated types (see [Localizable `displayName` and `slug`](https://strife.app/docs/reference/cli/schemas.md#localizable-displayname-and-slug)).

This is deliberately different from the type you'd get by statically inspecting a `defineType()` call's own shape (which describes what you write into the schema, not what you read back from the content API) — the generated types are the ones to build your frontend against.

## `strife typegen validate`

```sh
npx strife typegen validate [--config <path>] [-o | --output <path>] [--allow-missing-ids]
```

A CI-friendly check combining two things:

1. **Lint.** Two schemas that resolve to the same `collection` is a hard failure. A `reference`/`chapters` field whose target doesn't match any locally-defined type is a warning, not a failure — the target might be defined elsewhere, e.g. authored directly in Strife Studio. A `from: { id: process.env.X }` entry whose variable is unset is a failure — the template would lose its parent rule silently — unless you pass `--allow-missing-ids`, which demotes it to a warning. Both `generate` and `validate` load `.env.local` and `.env` from the current directory before reading the schemas — in a directory linked to a team, with that team's prefixed lines standing in for the plain names, as in `push`.
2. **Drift.** Regenerates the types in memory and compares them byte-for-byte against the file on disk at `--output`. A missing file or any difference fails the check with a pointer to re-run `generate`.

Typical usage is running `validate` in CI after `generate` has been run and committed, to catch schema changes that weren't followed by a regenerated types file. A CI checkout is usually not linked to a team (`strife link` keeps `.strife/` out of git), so no team-prefixed line applies there unless you commit `.strife/project.json`: set the plain variable a `from: { id }` reads in the CI environment, or pass `--allow-missing-ids`.

## Relationship to `push`

`typegen` and [`push`](https://strife.app/docs/reference/cli/commands.md#strife-push) both start from the same schema files but serve different purposes, and it's easy to conflate them:

* **`typegen generate`** produces local TypeScript types only. Nothing leaves your machine.
* **`push`** deploys your schema as real templates to a team in Strife Studio, plus the content index and (optionally) localization settings.

Neither command touches existing content documents.
