Schema

Generated TypeScript types

Generate deterministic TypeScript interfaces for your collections with myna types generate.

myna types generate turns canonical collection schemas into a standalone TypeScript module: one interface per collection plus a MynaCollections registry. Generation is pure and deterministic — the same schemas always yield byte-identical output, and no user-written files are ever touched.

$ myna types generate --out src/myna-types.ts

Options

Flag Effect
--schema-dir <dir> Read schemas from a specific local directory (default myna/, resolved against the linked project root).
--deployed Generate from the deployed schemas (latest version per collection) instead of local files.
--out <file> Write to a file; without it, the module is printed to stdout.

By default types come from your local schema files, loaded with the same conventions as myna schema diff. Use --deployed to match exactly what the API serves, regardless of local edits.

Output shape

Collections are sorted by name. Each becomes an export interface named as the PascalCase of the collection key (blog_postsBlogPosts), with a doc comment carrying the label and kind. Field descriptions become doc comments; optional fields (required: false) get ?. The module starts with a header comment and a JsonValue type alias, and ends with the registry:

export type JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue };

/** Blog posts (collection) */
export interface Posts {
  title: string;
  slug: string;
  status?: "draft" | "review" | "live";
  body: string;
  publishedAt?: string;
  cover?: string;
  author?: string;
  tags?: string[];
  seo?: {
    metaTitle?: string;
    metaDescription?: string;
  };
}

export interface MynaCollections {
  "posts": {
    fields: Posts;
    sortable: "title" | "slug" | "status" | "publishedAt";
    reference: "author";
  };
}

MynaCollections is the registry the SDK consumes. Alongside the field payload it records two things the field types alone cannot express:

  • sortable — the fields the query engine can order and filter by (scalars, excluding localized fields). A markdown body and a text title are both string, but only one of them can be sorted on, so the distinction has to be carried separately.
  • reference — the reference fields include can resolve.

Using them

Pass the registry to createMyna and the client stops returning Record<string, unknown>:

import { createMyna } from "@myna-sh/sdk";
import type { MynaCollections } from "./myna.generated";

const myna = createMyna<MynaCollections>({ project: "my-site" });

const posts = await myna.entries.list("posts", { order: "-publishedAt" });
posts.data[0].fields.title;        // string — no cast

The compiler then rejects what the API would reject at runtime:

await myna.entries.list("nope");                        // unknown collection
await myna.entries.list("posts", { order: "body" });    // markdown is not sortable
await myna.entries.list("posts", { filter: { body: "x" } });
await myna.entries.list("posts", { include: ["title"] }); // not a reference field
await myna.entries.list("posts", { fields: ["nope"] });

Passing no type parameter keeps the previous untyped behavior, so adopting this is opt-in and nothing breaks by ignoring it.

Type mapping

Field type Generated type
text string, or a string-literal union when enum is set
slug string
markdown string
number number
boolean boolean
date / datetime string (ISO date / ISO datetime with offset)
json JsonValue
asset string (asset id), string[] when multiple
reference string (entry id), string[] when multiple
object inline object type from its nested fields
list T[] where T follows the same mapping for the item kind (enum text items are parenthesized unions; object items are inline object types)

References and assets are ids, not expanded documents — resolve them through the SDK or API.

Commit the generated file. It is stable output, so diffs stay meaningful and CI can verify it is current:

$ myna schema push
$ myna types generate --out src/myna-types.ts
$ git add myna/ src/myna-types.ts && git commit -m "Add subtitle to posts"

Regenerate after every schema push; a clean git diff on the generated file after regenerating means your types match the schemas. The file header marks it as generated — do not edit it by hand.

Next