# generate-graph Source: https://docs.typesync.org/cli/generate-graph Generates a [Mermaid](https://mermaid.js.org) graph for the specified schema and injects it into the specified Markdown file. The generated graph is the visual representation of the database architecture inferred from your schema. You can specify where the graph is inserted within the file using the `--startMarker` and `--endMarker` options. For a detailed guide, see the full [example](#example) below. ## Usage ```bash theme={null} typesync generate-graph --definition --outFile --startMarker --endMarker --orientation --debug ``` ## Options The exact path or a Glob pattern to the definition file or files. Each definition file must be a YAML or JSON file containing model definitions. * Example single file path: `definition/models.json` * Example Glob pattern: `'definition/**/*.yml'` The path to the output file. A marker that indicates the line after which the generated code should be inserted. Make sure to use a string that is unique within the file. The line containing the marker must be commented i.e. the marker needs to appear after the ` This graph is automatically generated. ``` To generate a Mermaid graph for the defined models and inject them between the `typesync-start` and `typesync-end` markers in the `graph.md` file, you can run the following command: ```bash theme={null} typesync generate-graph --definition definition.yml --outFile graph.md --startMarker typesync-start --endMarker typesync-end ``` Once you run the command, Typesync inserts the Mermaid graph definition into the specified section. ````md graph.md theme={null} # Architecture This graph explains how our database is structured. ```mermaid graph LR node1["authors"] --> node2["{authorId}"] node3["books"] --> node4["{bookId}"] node4["{bookId}"] --> node5["chapters"] node5["chapters"] --> node6["{chapterId}"] node4["{bookId}"] --> node7["reviews"] node7["reviews"] --> node8["{reviewId}"] node4["{bookId}"] --> node9["translations"] node9["translations"] --> node10["{translationId}"] `` This graph is automatically generated. ``` ```` The graph generated for the above schema looks as follows: ```mermaid theme={null} graph LR node1["authors"] --> node2["{authorId}"] node3["books"] --> node4["{bookId}"] node4["{bookId}"] --> node5["chapters"] node5["chapters"] --> node6["{chapterId}"] node4["{bookId}"] --> node7["reviews"] node7["reviews"] --> node8["{reviewId}"] node4["{bookId}"] --> node9["translations"] node9["translations"] --> node10["{translationId}"] ``` # generate-py Source: https://docs.typesync.org/cli/generate-py Generates Python/Pydantic type definitions for the specified schema and writes them to the specified file. Typesync first “flattens” your schema, creating new aliases for inline types defined within. It then generates the classes, enums, aliases, etc. including serializers and deserializers. ## Usage ```bash theme={null} typesync generate-py --definition --target --outFile --indentation --customPydanticBase --debug ``` ## Options The exact path or a Glob pattern to the definition file or files. Each definition file must be a YAML or JSON file containing model definitions. * Example single file path: `definition/models.json` * Example Glob pattern: `'definition/**/*.yml'` The target environment for which the types are generated. This option specifies the target SDK and version, ensuring that the output is compatible with the chosen environment. See the list of available targets [here](#targets). The path to the output file. The base class from which all the generated Python models will extend. The base class must extend `pydantic.BaseModel` and the option must be provided in the format `x.y.ModelName`. If this option is not provided, the generated models will extend from `pydantic.BaseModel`. Example values: * `custom.MyModel` * `a.b.c.MyCustomModel` The name of the sentinel value used to indicate that a field should be missing from a given object. This is generated as a variable alongside your model definitions. Indentation or tab width for the generated code. Whether to enable debug logs. ## Targets * `firebase-admin@6`: For Python projects that rely on the [Firebase Admin Python SDK (v6)](https://github.com/firebase/firebase-admin-python). # generate-rules Source: https://docs.typesync.org/cli/generate-rules Generates validator functions for Firestore Security Rules (version 2) and injects them into the specified file. These validators ensure that request data adheres to defined model interfaces and detect any modifications to read-only fields during write operations. Since Security Rules are centralized in a single file (typically `firestore.rules`), and developers often implement custom rules alongside type validations, Typesync inserts only the necessary validator functions, without overriding your custom rules. You can specify where these validators are added within the file using the `--startMarker` and `--endMarker` options. For a detailed guide, see the full [example](#example) below. Note that these validators must adhere to the intrinsic limitations of Security Rules. For example, while it's feasible to verify if `x` is a list with the `x is list` predicate, determining whether it's a list of strings is not possible since loop constructs are not available in Security Rules. Typesync will provide the most stringent validation possible within these constraints. ## Usage ```bash theme={null} typesync generate-rules --definition --outFile --startMarker --endMarker --typeValidatorNamePattern --typeValidatorParamName --indentation --debug ``` ## Options The exact path or a Glob pattern to the definition file or files. Each definition file must be a YAML or JSON file containing model definitions. * Example single file path: `definition/models.json` * Example Glob pattern: `'definition/**/*.yml'` The path to the output file. A marker that indicates the line after which the generated code should be inserted. Make sure to use a string that is unique within the file. The line containing the marker must be commented i.e. the marker needs to appear after the `//` (see [example](#example)). A marker that indicates the line before which the generated code should be inserted. Make sure to use a string that is unique within the file. The line containing the marker must be commented i.e. the marker needs to appear after the `//` (see [example](#example)). The pattern that specifies how the generated type validators are named. The pattern must be a string that contains the `"{modelName}"` substring (this is a literal value). Example values: * `"isValid{modelName}"` -> produces validators like `isValidUser`, `isValidProject`, `isValidAccount` etc. * `"is{modelName}"` -> produces validators like `isUser`, `isProject`, `isAccount` etc. The name of the parameter taken by each type validator. Indentation or tab width for the generated code. Whether to enable debug logs. ## Example Suppose you have a schema definition file named `models.yml` and a Security Rules file named `firestore.rules`. ```yaml models.yml theme={null} # yaml-language-server: $schema=https://schema.typesync.org/v0.18.json UserRole: model: alias docs: Represents a user's role within a project. type: type: enum members: - label: Owner value: owner - label: Admin value: admin - label: Member value: member User: model: document path: users/{userId} docs: Represents a user that belongs to a project. type: type: object fields: username: type: string docs: A string that uniquely identifies the user within a project. role: type: UserRole website_url: type: string optional: true created_at: type: timestamp ``` ```javascript firestore.rules (initial) theme={null} rules_version = '2'; service cloud.firestore { // typesync-start // typesync-end // Here you define your custom rules match /databases/{database}/documents { match /users/{uid} { allow read; allow write: if isValidUser(request.resource.data); } } } ``` To generate validators for the defined models and inject them between the `typesync-start` and `typesync-end` markers in the `firestore.rules` file, you can run the following command: ```bash theme={null} typesync generate-rules --definition definition.yml --outFile firestore.rules --startMarker typesync-start --endMarker typesync-end ``` Typesync will insert the `isValidUserRole()` and `isValidUser()` validators into the file. You can then use these validators as needed in your custom rules. ```javascript firestore.rules theme={null} rules_version = '2'; service cloud.firestore { // typesync-start function isValidUserRole(data) { return ((data == 'owner') || (data == 'admin') || (data == 'member')); } function isValidUser(data) { return ( (data is map) && (data.keys().hasOnly(['username', 'role', 'website_url', 'created_at'])) && (data.username is string) && isValidUserRole(data.role) && ((data.website_url is string) || !('website_url' in data)) && (data.created_at is timestamp) ); } // typesync-end // Here you define your custom rules match /databases/{database}/documents { match /users/{uid} { allow read; allow write: if isValidUser(request.resource.data); } } } ``` # generate-swift Source: https://docs.typesync.org/cli/generate-swift Generates Swift type definitions for the specified schema and writes them to the specified file. Typesync first "flattens" your schema, creating new aliases for inline types defined within. It then generates the primary and auxiliary structs, enums, aliases, encoders, and decoders. For document models, generated Swift structs include an `@DocumentID var id: String?` property by default. The Firebase Apple SDK fills this value from the document path when decoding and excludes it from the encoded document body when writing. ## Usage ```bash theme={null} typesync generate-swift --definition --target --outFile --indentation --debug ``` ## Options The exact path or a Glob pattern to the definition file or files. Each definition file must be a YAML or JSON file containing model definitions. * Example single file path: `definition/models.json` * Example Glob pattern: `'definition/**/*.yml'` The target environment for which the types are generated. This option specifies the target SDK and version, ensuring that the output is compatible with the chosen environment. See the list of available targets [here](#targets). The path to the output file. Indentation or tab width for the generated code. Whether to enable debug logs. ## Targets * `firebase@10`: For Swift projects that rely on the [Firebase Apple SDK (v10)](https://github.com/firebase/firebase-ios-sdk). ## Document IDs Document model structs import `FirebaseFirestore` and include an `@DocumentID` property: ```swift theme={null} import FirebaseFirestore struct User: Codable { @DocumentID var id: String? var username: String } ``` If a document body already has a Firestore field named `id`, rename the generated document ID property on that document model: ```yaml theme={null} User: model: document path: users/{userId} swift: documentIdProperty: name: documentId type: type: object fields: id: type: string username: type: string ``` This produces `@DocumentID var documentId: String?` while keeping the body field named `id`. ## Swift field names Use `swift.name` on a field when the generated Swift property name should differ from the Firestore field name. Typesync keeps encoding and decoding aligned with the original Firestore key through `CodingKeys`. ```yaml theme={null} User: model: document path: users/{userId} type: type: object fields: class: type: string swift: name: userClass ``` Typesync fails generation if two fields resolve to the same Swift property name, or if a body field conflicts with the generated `@DocumentID` property. Rename one of the properties with `swift.name` or `swift.documentIdProperty.name`. # generate-ts Source: https://docs.typesync.org/cli/generate-ts Generates TypeScript type definitions for the specified schema and writes them to the specified file. ## Usage ```bash theme={null} typesync generate-ts --definition --target --outFile --indentation --debug ``` ## Options The exact path or a Glob pattern to the definition file or files. Each definition file must be a YAML or JSON file containing model definitions. * Example single file path: `definition/models.json` * Example Glob pattern: `'definition/**/*.yml'` The target environment for which the types are generated. This option specifies the target SDK and version, ensuring that the output is compatible with the chosen environment. See the list of available targets [here](#targets). The path to the output file. Controls how objects are defined in the TypeScript output. Object types can be represented either by interfaces or type aliases. Indentation or tab width for the generated code. Whether to enable debug logs. ## Targets * `firebase-admin@13`: For backend projects that use [Firebase Admin Node.js SDK (v13)](https://www.npmjs.com/package/firebase-admin). * `firebase-admin@12`: For backend projects that use [Firebase Admin Node.js SDK (v12)](https://www.npmjs.com/package/firebase-admin). * `firebase-admin@11`: For backend projects that use [Firebase Admin Node.js SDK (v11)](https://www.npmjs.com/package/firebase-admin). * `firebase-admin@10`: For backend projects that use [Firebase Admin Node.js SDK (v10)](https://www.npmjs.com/package/firebase-admin). * `firebase@11`: For frontend projects that use [Firebase Javascript SDK (v11)](https://www.npmjs.com/package/firebase). * `firebase@10`: For frontend projects that use [Firebase Javascript SDK (v10)](https://www.npmjs.com/package/firebase). * `firebase@9`: For frontend projects that use [Firebase Javascript SDK (v9)](https://www.npmjs.com/package/firebase). * `react-native-firebase@21`: For React Native projects that use [React Native Firebase (v21)](https://www.npmjs.com/package/@react-native-firebase/firestore). * `react-native-firebase@20`: For React Native projects that use [React Native Firebase (v20)](https://www.npmjs.com/package/@react-native-firebase/firestore). * `react-native-firebase@19`: For React Native projects that use [React Native Firebase (v19)](https://www.npmjs.com/package/@react-native-firebase/firestore). # generate-zod Source: https://docs.typesync.org/cli/generate-zod Generates [Zod](https://zod.dev) schemas for the specified Typesync schema and writes them to the specified file. The generator can produce code for either Zod v3 or v4, and can optionally emit inferred TypeScript types alongside the schemas. ## Usage ```bash theme={null} typesync generate-zod --definition --target --outFile --variant --schemaNamePattern --emitInferredTypes --inferredTypeNamePattern --indentation --debug ``` ## Options The exact path or a Glob pattern to the definition file or files. Each definition file must be a YAML or JSON file containing model definitions. * Example single file path: `definition/models.json` * Example Glob pattern: `'definition/**/*.yml'` The target environment for which the types are generated. This option specifies the target SDK and version, ensuring that the output is compatible with the chosen environment. See the list of available targets [here](#targets). The path to the output file. Which Zod major release the generated code should target. Pick the variant that matches the `zod` version installed in the consuming project. The two majors differ in a couple of API surface points (the `z.record` key argument and the strict / loose object factories) and the generator emits the right shape for each. The pattern that controls how the generated Zod schema constants are named. The pattern must be a string that contains the `"{modelName}"` substring (this is a literal value). Example values: * `"{modelName}Schema"` → produces exports like `UserSchema`, `PostSchema`, `AccountSchema` etc. * `"z{modelName}"` → produces exports like `zUser`, `zPost`, `zAccount` etc. When enabled, the generator emits an inferred TypeScript type alongside each Zod schema. For a model named `User` with the default patterns, the output becomes: ```ts theme={null} export const UserSchema = z.strictObject({ /* ... */ }); export type User = z.infer; ``` The pattern that controls how the inferred TypeScript types are named when `--emitInferredTypes` is set. The pattern must contain the literal substring `"{modelName}"`. Ignored when `--emitInferredTypes` is not set. Example values: * `"{modelName}"` → produces types like `User`, `Post`, `Account` etc. * `"{modelName}Type"` → produces types like `UserType`, `PostType`, `AccountType` etc. * `"I{modelName}"` → produces types like `IUser`, `IPost`, `IAccount` etc. Indentation or tab width for the generated code. Whether to enable debug logs. ## Targets `generate-zod` reuses the `generate-ts` target list. The `--target` option determines the runtime classes that the generated `z.instanceof(...)` checks resolve to — pick the target that matches the Firestore SDK you decode documents with. * `firebase-admin@13`: For backend projects that use [Firebase Admin Node.js SDK (v13)](https://www.npmjs.com/package/firebase-admin). * `firebase-admin@12`: For backend projects that use [Firebase Admin Node.js SDK (v12)](https://www.npmjs.com/package/firebase-admin). * `firebase-admin@11`: For backend projects that use [Firebase Admin Node.js SDK (v11)](https://www.npmjs.com/package/firebase-admin). * `firebase-admin@10`: For backend projects that use [Firebase Admin Node.js SDK (v10)](https://www.npmjs.com/package/firebase-admin). * `firebase@11`: For frontend projects that use [Firebase Javascript SDK (v11)](https://www.npmjs.com/package/firebase). * `firebase@10`: For frontend projects that use [Firebase Javascript SDK (v10)](https://www.npmjs.com/package/firebase). * `firebase@9`: For frontend projects that use [Firebase Javascript SDK (v9)](https://www.npmjs.com/package/firebase). * `react-native-firebase@21`: For React Native projects that use [React Native Firebase (v21)](https://www.npmjs.com/package/@react-native-firebase/firestore). * `react-native-firebase@20`: For React Native projects that use [React Native Firebase (v20)](https://www.npmjs.com/package/@react-native-firebase/firestore). * `react-native-firebase@19`: For React Native projects that use [React Native Firebase (v19)](https://www.npmjs.com/package/@react-native-firebase/firestore). ## Notes * References between models are emitted as `z.lazy(() => OtherSchema)`. Using `z.lazy` defers identifier resolution until validation time, which keeps mutually recursive schemas working regardless of declaration order in the generated file. * Strict / loose objects map to `z.strictObject` / `z.looseObject` for v4 and to `z.object(...).strict()` / `z.object(...).passthrough()` for v3. Whether an object accepts additional fields is controlled by the `additionalFields` flag in the schema definition. * The Firestore SDK is only imported when at least one model uses `timestamp` or `bytes`. For the admin targets, `bytes` resolves to the Node global `Buffer` and does not trigger an SDK import on its own. # validate Source: https://docs.typesync.org/cli/validate Checks if the specified schema definition is syntactically valid. This command validates the schema files themselves. To validate documents that already exist in Firestore, use [validate-data](/cli/validate-data). ## Usage ```bash theme={null} typesync validate --definition --debug ``` ## Options The exact path or a Glob pattern to the definition file or files. Each definition file must be a YAML or JSON file containing model definitions. * Example single file path: `definition/models.json` * Example Glob pattern: `'definition/**/*.yml'` Whether to enable debug logs. # validate-data Source: https://docs.typesync.org/cli/validate-data Validate live Firestore documents against your Typesync schema. Traverses Firestore collections for selected document models and validates each document against a Zod validator built from your Typesync schema. The command reports invalid documents and does not write to Firestore. You must explicitly choose what to scan with one or more `--model` flags or with `--all-models`. `validate-data` can read every document in the selected collections. Collections can contain hundreds of thousands of documents, so a full scan can be slow and can incur Firestore read costs. Run this command when you need to audit or investigate stored data, not as a routine development or deployment step. ## Usage ```bash theme={null} typesync validate-data --definition --model ``` ```bash theme={null} typesync validate-data --definition 'definition/**/*.yml' --model User --model Post --serviceAccount ./service-account.json ``` ## Options The exact path or a Glob pattern to the definition file or files. Each definition file must be a YAML or JSON file containing model definitions. * Example single file path: `definition/models.json` * Example Glob pattern: `'definition/**/*.yml'` The document model to validate. Repeat the flag to validate multiple models. Mutually exclusive with `allModels`. Validates every document model in the schema. This is opt-in because scanning a large Firestore project can be slow and can incur read costs. Mutually exclusive with `model`. Path to a Google Cloud service account JSON file. If omitted, Typesync uses the `GOOGLE_APPLICATION_CREDENTIALS` environment variable when it is set. Overrides the Firebase project ID. This is most useful when validating data in the Firestore emulator. Points the validator at the Firestore emulator instead of a live project. Use a `host:port` value such as `localhost:8080`. Maximum retry attempts per batch for transient Firestore errors. Number of documents fetched per page during traversal. Stops validation for each selected model after this many documents. Use this for spot checks on large collections. Writes the full JSON validation report to the specified file. Prints a JSON summary to stdout instead of rendering the live progress UI. Whether to enable debug logs. ## Examples ### Validate selected models ```bash theme={null} typesync validate-data \ --definition 'definition/**/*.yml' \ --model User \ --model Post \ --serviceAccount ./service-account.json ``` ### Validate all document models ```bash theme={null} typesync validate-data \ --definition 'definition/**/*.yml' \ --all-models \ --serviceAccount ./service-account.json ``` ### Validate emulator data ```bash theme={null} typesync validate-data \ --definition 'definition/**/*.yml' \ --model User \ --projectId demo-project \ --emulatorHost localhost:8080 ``` ### Write a report file ```bash theme={null} typesync validate-data \ --definition 'definition/**/*.yml' \ --all-models \ --json \ --outFile validation-report.json ``` The command exits with code `1` when it finds invalid documents. It exits with code `2` when the validation run itself fails, such as when credentials are missing or a selected model does not exist. ## Traversal support Typesync can validate top-level collections and nested subcollections whose collection-name segments are literal strings. For example, `users/{userId}/posts/{postId}` can be traversed because the collection names are `users` and `posts`. Model paths with placeholder collection-name segments cannot be traversed by the current implementation because Firestore collection-group queries require a literal collection ID. # Installation Source: https://docs.typesync.org/installation You can install the Typesync CLI either globally or on a per-project basis (locally) depending on your use case. Both options are perfectly valid but, when possible, it's a good idea to install it locally to explicitly tie your project to a specific Typesync CLI version. **Prerequisite:** The Typesync CLI requires [Node.js](https://nodejs.org) 18 or above to be installed on your machine. ```bash Global theme={null} npm i -g typesync-cli ``` ```bash Local (Node.js projects) theme={null} npm i typesync-cli ``` # Introduction Source: https://docs.typesync.org/introduction Learn what Typesync does for Firestore schema management, code generation, and data validation. Typesync is an open-source schema management toolkit for [Firestore](https://cloud.google.com/firestore) databases. You maintain a single source of truth for your Firestore architecture in a *schema*, then use the CLI to generate code and validate data from that schema. Typesync helps keep your database, generated application code, and validation checks aligned as your schema changes. ## How Typesync helps you * **Generate application models** for TypeScript, Swift, and Python from the same Firestore schema. * **Validate live Firestore data** against your schema with `typesync validate-data`, using generated Zod validators under the hood. * **Generate Security Rules validators** so Firestore writes can be checked against the same model definitions. * **Visualize your database architecture** by generating Mermaid graphs from document model paths. * **Document your data models** with schema-level descriptions that flow into generated output. ## Typesync in 30 seconds You define your Firestore schema in a collection of YAML/JSON files. The Typesync CLI reads these files and produces ready-to-use Firestore model definitions for all the languages and platforms you work with. In the example below, we define our models in `models.yml`. ```yaml models.yml theme={null} # yaml-language-server: $schema=https://schema.typesync.org/v0.18.json UserRole: model: alias docs: Represents a user's role within a project. type: type: enum members: - label: Owner value: owner - label: Admin value: admin - label: Member value: member User: model: document path: users/{userId} docs: Represents a user that belongs to a project. type: type: object fields: username: type: string docs: A string that uniquely identifies the user within a project. role: type: UserRole website_url: type: string optional: true created_at: type: timestamp ``` We then run the following commands to generate type definitions for four different environments, generate type validators for Security Rules, and validate existing Firestore data: ```bash TS (frontend) theme={null} typesync generate-ts --target firebase@10 --definition models.yml # ... other options ``` ```bash TS (backend) theme={null} typesync generate-ts --target firebase-admin@11 --definition models.yml # ... other options ``` ```bash Swift theme={null} typesync generate-swift --target firebase@10 --definition models.yml # ... other options ``` ```bash Python theme={null} typesync generate-py --target firebase-admin@6 --definition models.yml # ... other options ``` ```bash Security Rules theme={null} typesync generate-rules --definition models.yml # ... other options ``` ```bash Data validation theme={null} typesync validate-data --definition models.yml --model User # ... other options ``` The generator commands produce the following files: ```ts models.ts (frontend) theme={null} import type * as firestore from 'firebase/firestore'; /** Represents a user's role within a project. */ export type UserRole = 'owner' | 'admin' | 'member'; /** Represents a user that belongs to a project. */ export interface User { /** A string that uniquely identifies the user within a project. */ username: string; role: UserRole; website_url?: string; created_at: firestore.Timestamp; } ``` ```ts models.ts (backend) theme={null} import type { firestore } from 'firebase-admin'; /** Represents a user's role within a project. */ export type UserRole = 'owner' | 'admin' | 'member'; /** Represents a user that belongs to a project. */ export interface User { /** A string that uniquely identifies the user within a project. */ username: string; role: UserRole; website_url?: string; created_at: firestore.Timestamp; } ``` ```swift models.swift theme={null} import Foundation import FirebaseFirestore /// Represents a user's role within a project. enum UserRole: String, Codable { case Owner = "owner" case Admin = "admin" case Member = "member" } /// Represents a user that belongs to a project. struct User: Codable { @DocumentID var id: String? /// A string that uniquely identifies the user within a project. var username: String var role: UserRole var websiteUrl: String? var createdAt: Date private enum CodingKeys: String, CodingKey { case username case role case websiteUrl = "website_url" case createdAt = "created_at" } } ``` ```python models.py theme={null} from __future__ import annotations import typing import datetime import enum import pydantic # [static declarations redacted for brevity] class UserRole(enum.Enum): """Represents a user's role within a project.""" Owner = "owner" Admin = "admin" Member = "member" class User(TypesyncModel): """Represents a user that belongs to a project.""" username: str """A string that uniquely identifies the user within a project.""" role: UserRole website_url: typing.Union[TypesyncUndefined, str] = UNDEFINED created_at: datetime.datetime class Config: use_enum_values = True extra = 'forbid' def __setattr__(self, name: str, value: typing.Any) -> None: if name == "website_url" and value is None: raise ValueError("'website_url' field cannot be set to None") super().__setattr__(name, value) ``` ```javascript firestore.rules theme={null} rules_version = '2'; service cloud.firestore { // typesync-start function isValidUserRole(data) { return ((data == 'owner') || (data == 'admin') || (data == 'member')); } function isValidUser(data) { return ( (data is map) && (data.keys().hasOnly(['username', 'role', 'website_url', 'created_at'])) && (data.username is string) && isValidUserRole(data.role) && ((data.website_url is string) || !('website_url' in data)) && (data.created_at is timestamp) ); } // typesync-end // Here you define your custom rules match /databases/{database}/documents { match /users/{uid} { allow read; allow write: if isValidUser(request.resource.data); } } } ``` Once we have the generated models, we can import and use them in our application code. As for Security Rules, we just need to deploy them to Firestore. ```ts app.ts (frontend) theme={null} import { type CollectionReference, collection, doc, getDoc, getFirestore } from 'firebase/firestore'; import type { User } from './models'; const firestore = getFirestore(); const usersColRef = collection(firestore, 'users') as CollectionReference; const userDocRef = doc(usersColRef, 'adam'); const userSnap = await getDoc(userDocRef); const user = userSnap.data(); // is a User object ``` ```ts app.ts (backend) theme={null} import { firestore } from 'firebase-admin'; import type { User } from './models'; const usersColRef = firestore().collection('users') as firestore.CollectionReference; const userSnap = await usersColRef.doc('adam').get(); const user = userSnap.data(); // is a User object ``` ```swift app.swift theme={null} import Firebase let db = Firestore.firestore() db.document("users/adam").getDocument { snapshot, err in if let user = try! snapshot?.data(as: User.self) { print(user.id) // "adam" } } ``` ```python app.py theme={null} from firebase_admin import firestore from models import User, UserRole db = firestore.client() doc_ref = db.collection('users').document('adam') snapshot = doc_ref.get() user = User.model_validate(snapshot.to_dict()) # is a User instance ``` ## Design Goals Typesync is built on three core principles that guide its design and functionality. ### 1. Predictability Typesync values straightforward operation over complexity. It doesn't try to outsmart you by making implicit assumptions. There are no "gotchas", no hidden configurations. When faced with bad input, Typesync prefers to issue an error rather than make assumptions and try to make the most of the situation. Our philosophy is straightforward: developer tools should consistently perform as expected, without any surprising behavior—even if such behavior might be seen as beneficial to some. Essentially, tools should remain "dumb" in their operations, even while performing complex tasks. The predictability that this behavior produces means that you always know what to expect from Typesync as it does only what it promises to do. Nothing more, nothing less. ### 2. Ejectability Flexibility is central to Typesync's design. It's developed to be non-intrusive, with no lock-in effects. You can easily integrate Typesync into your projects without major changes to your codebase. Typesync *is not* a library that tightly attaches itself to your code. You can eject at any time by simply copy-pasting the generated output into your source code without having to refactor your code. Moving away from Typesync is as simple as integrating it. ### 3. Configurability Everything that can be reasonably expected to be configurable is made explicitly configurable by Typesync. Whether it's defining how your schema is structured or customizing the output for different programming languages, Typesync provides you with the flexibility to make those decisions. Typesync is designed to be as customizable as possible, allowing you to tailor the tool to your project's requirements. # Quickstart Source: https://docs.typesync.org/quickstart First, ensure you have [Node.js](https://nodejs.org) 18+ installed. Then, install the Typesync CLI using npm: ```bash theme={null} npm install -g typesync-cli ``` Create a directory within your project to store your Typesync definition files. A common practice is to name this directory `definition`. ```bash theme={null} mkdir definition cd definition ``` Next, create a YAML file named `models.yml` in the `definition` directory. This file will contain the schema definitions for your Firestore documents. Here's a sample schema: You can also define your models in JSON files. Typesync accepts YAML, JSON or even a combination of both! ```yaml models.yml theme={null} # yaml-language-server: $schema=https://schema.typesync.org/v0.18.json UserRole: model: alias docs: Represents a user's role within a project. type: type: enum members: - label: Owner value: owner - label: Admin value: admin - label: Member value: member User: model: document path: users/{userId} docs: Represents a user that belongs to a project. type: type: object fields: username: type: string docs: A string that uniquely identifies the user within a project. role: type: UserRole website_url: type: string optional: true created_at: type: timestamp ``` You can now generate the types for the relevant environment. For example, if your project is a Node.js backend that uses Firebase Admin SDK (version 11), run the following command: ```bash theme={null} typesync generate-ts --definition 'definition/**/*.yml' --target firebase-admin@11 --outFile models.ts ``` This command tells Typesync to: * take all `.yml` files in the `definition` directory as the schema definition * generate TypeScript interfaces for use with the Firebase Admin SDK (version 11) * write the generated types to the `models.ts` file in the current directory Here's what the generated TypeScript file might look like: ```ts models.ts (backend) theme={null} import type { firestore } from 'firebase-admin'; /** Represents a user's role within a project. */ export type UserRole = 'owner' | 'admin' | 'member'; /** Represents a user that belongs to a project. */ export interface User { /** A string that uniquely identifies the user within a project. */ username: string; role: UserRole; website_url?: string; created_at: firestore.Timestamp; } ``` You should regenerate your types anytime the schema changes. To streamline development, consider integrating the Typesync generation command into your build process or CI/CD pipeline. ### Version Control Decide if you want to version control the generated files. It can be beneficial for ensuring consistency across environments but may require additional maintenance. ### Multiple Files As your project grows, you might want to split your schema into multiple YAML/JSON files. Typesync will automatically handle all files matching the pattern that you provide to it through the `--definition` option. # Definition Source: https://docs.typesync.org/schema/definition The Typesync schema for a project is defined in a collection of YAML/JSON files. Your definition can contain as many model definition files as you need and you can organize them any way you want. Each top-level field in a definition file must refer to a model name and the corresponding value must be the model definition. There are two types of models that you can define in a model definition file: *document models* and *alias models*. ## Document models A document model represents the shape of a document in a particular Firestore collection. A literal field that specifies that this is a `document` model. An exact or generic path to the document. Must be a string consisting of path segments separated by a `/` (slash). Each segment can either be a literal ID or a generic ID of the collection or document. A literal ID is a plain string, such as `users`, while a generic ID must be enclosed in curly braces (e.g. `{userId}`). Example values: * `projects/{projectId}`: A document in a top-level `projects` collection. * `users/{userId}/posts/{postId}`: A document in a `posts` sub-collection. * `static/data/authors/{authorId}`: A document in a static `authors` sub-collection. * `{rootColId}/{docId}/cities/london`: A document with a specific ID in a `cities` sub-collection. Optional documentation explaining the model in more detail. Typesync will add this to the doc comments for the generated models. The type representing the shape of the document. A document can be represented only by an [object](/schema/types#object) type. Swift-specific overrides for this document model. Renames the auto-generated `@DocumentID` property in Swift output for this document model. Use this when the document body already has a Firestore field named `id`, or when you prefer a different Swift property name such as `documentId`. ### Example ```yaml user.yml theme={null} # yaml-language-server: $schema=https://schema.typesync.org/v0.18.json User: model: document path: users/{userId} docs: Represents a user that belongs to a project. type: type: object fields: name: type: string docs: The full name of the user. created_at: type: timestamp ``` ## Alias models An alias model is used for convenience purposes to define reusable type aliases. You can use the same alias model in multiple document models. You can also use alias models when composing other aliases. A literal field that specifies that this is an `alias` model. Optional documentation explaining the model in more detail. Typesync will add this to the doc comments for the generated models. The type of which this model is an alias. Can be any Typesync [type](/schema/types). ### Example ```yaml user.yml theme={null} # yaml-language-server: $schema=https://schema.typesync.org/v0.18.json UserRole: model: alias docs: Represents a user's role within a project. type: type: enum members: - label: Owner value: owner - label: Admin value: admin - label: Member value: member ``` ## Autcomplete/Intellisense When writing your schema definition in YAML, always include the following line at the top of each definition file. ```yaml theme={null} # yaml-language-server: $schema=https://schema.typesync.org/v0.18.json ``` This indicates to your IDE that the file is not just any YAML file but a part of a Typesync definition by linking it to the relevant JSON Schema.. This will allow your IDE to provide Intellisense/autocomplete for definition fields. For type hinting to take effect, you may need to install a YAML extension that automatically loads the specified JSON Schema. For VS Code, we recommend using the [YAML](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml) extension by Red Hat. When writing your schema definition in JSON, always include the following top-level field at the top of each definition file. ```json theme={null} { "$schema": "https://schema.typesync.org/v0.18.json" // ... } ``` This indicates to your IDE that the file is not just any JSON file but a part of a Typesync definition by linking it to the relevant JSON Schema. This will allow your IDE to provide Intellisense/autocomplete for definition fields. For type hinting to take effect, you may need to install an extension that automatically loads the specified JSON Schema. For VS Code, you shouldn't need any extensions as it [ships with JSON Schema support](https://code.visualstudio.com/docs/languages/json#_json-schemas-and-settings). For the time being, you need manually synchronize the schema version in this line with the Typesync version you're using. For example, if you're using Typesync version 0.4.2, you need to make sure that the version in the above schema URL is `v0.4`. Patch version is always excluded. ## Validating with CLI While utilizing a JSON schema can help identify syntax errors within your schema definition, the Typesync CLI provides the most reliable method to check if a definition is syntactically valid. To validate a schema definition, use the `validate` command as shown below: ```bash theme={null} typesync validate --definition ``` For additional details on using this command, see [validate](/cli/validate). Typesync automatically validates your definition before running any generators. The manual validation command is needed when you just want to check if your schema definition is valid without generating any artifacts. # Types Source: https://docs.typesync.org/schema/types Here, you'll find a comprehensive list of all types supported by the Typesync specification. Typesync's powerful type system is designed to support a wide array of complex and useful types. ## `any` Represents any type. ```yaml definition.yml theme={null} Example: model: alias type: any ``` ```ts models.ts theme={null} export type Example = any; ``` ```swift models.swift theme={null} typealias Example = Any ``` ```python models.py theme={null} import typing Example = typing.Any ``` ```javascript firestore.rules theme={null} function isValidExample(data) { return true; } ``` ## `unknown` Represents an unknown type. ```yaml definition.yml theme={null} Example: model: alias type: unknown ``` ```ts models.ts theme={null} export type Example = unknown; ``` ```swift models.swift theme={null} typealias Example = Any ``` ```python models.py theme={null} import typing Example = typing.Any ``` ```javascript firestore.rules theme={null} function isValidExample(data) { return true; } ``` ## `nil` Represents the explicit absence of a value. ```yaml definition.yml theme={null} Example: model: alias type: nil ``` ```ts models.ts theme={null} export type Example = null; ``` ```python models.py theme={null} Example = None ``` ```javascript firestore.rules theme={null} function isValidExample(data) { return true; } ``` ## `string` Represents a string value. ```yaml definition.yml theme={null} Example: model: alias type: string ``` ```ts models.ts theme={null} export type Example = string; ``` ```swift models.swift theme={null} typealias Example = String ``` ```python models.py theme={null} Example = str ``` ```javascript firestore.rules theme={null} function isValidExample(data) { return (data is string); } ``` ## `boolean` Represents a boolean value. ```yaml definition.yml theme={null} Example: model: alias type: boolean ``` ```ts models.ts theme={null} export type Example = boolean; ``` ```swift models.swift theme={null} typealias Example = Bool ``` ```python models.py theme={null} Example = bool ``` ```javascript firestore.rules theme={null} function isValidExample(data) { return (data is bool); } ``` ## `int` Represents a signed integer. ```yaml definition.yml theme={null} Example: model: alias type: int ``` ```ts models.ts theme={null} export type Example = number; ``` ```swift models.swift theme={null} typealias Example = Int ``` ```python models.py theme={null} Example = int ``` ```javascript firestore.rules theme={null} function isValidExample(data) { return (data is int); } ``` ## `double` Represents a double-precision floating point number. ```yaml definition.yml theme={null} Example: model: alias type: double ``` ```ts models.ts theme={null} export type Example = number; ``` ```swift models.swift theme={null} typealias Example = Double ``` ```python models.py theme={null} Example = float ``` ```javascript firestore.rules theme={null} function isValidExample(data) { return (data is float); } ``` ## `timestamp` Represents a datetime value. ```yaml definition.yml theme={null} Example: model: alias type: timestamp ``` ```ts models.ts theme={null} export type Example = firestore.Timestamp; ``` ```swift models.swift theme={null} typealias Example = Date ``` ```python models.py theme={null} import datetime Example = datetime.datetime ``` ```javascript firestore.rules theme={null} function isValidExample(data) { return (data is timestamp); } ``` ## `bytes` Represents a Firestore bytes value. ```yaml definition.yml theme={null} Example: model: alias type: bytes ``` ```ts models.ts theme={null} // Firebase Web targets emit firestore.Bytes; React Native Firebase emits firestore.Blob. export type Example = Buffer; ``` ```swift models.swift theme={null} typealias Example = Data ``` ```python models.py theme={null} Example = bytes ``` ```javascript firestore.rules theme={null} function isValidExample(data) { return (data is bytes); } ``` ## `document-reference` Represents a Firestore [document reference](https://firebase.google.com/docs/reference/js/firestore_.documentreference) — a pointer to another Firestore document. Use this in place of storing a document ID as a `string` when you want the field to round-trip as a native reference under each Firestore SDK. Firestore only supports storing **document** references in document fields, not collection references — the stored value's path must end on a document id. The type name mirrors the SDK class `DocumentReference` to make this constraint obvious at the schema-definition layer. Without an explicit `model`, the `document-reference` type intentionally does not encode the target document's shape. If you want the generated TypeScript and Zod types to be narrowed to a specific target model, use the parameterized form below. ```yaml definition.yml theme={null} Example: model: alias type: document-reference ``` ```ts models.ts theme={null} export type Example = firestore.DocumentReference; ``` ```swift models.swift theme={null} typealias Example = DocumentReference ``` ```python models.py theme={null} Example = firestore.DocumentReference ``` ```javascript firestore.rules theme={null} function isValidExample(data) { return (data is path); } ``` ### Parameterized form `document-reference` also accepts an object form with an optional `model` field that names the target document (or alias) model. Typesync validates that the referenced model exists in the same schema and threads the target through to the generated code. The narrowing only takes effect on platforms whose Firestore SDK class is generic: * **TypeScript** — `firestore.DocumentReference` is emitted instead of `firestore.DocumentReference`. * **Zod** — the inferred type from `z.infer` carries the same narrowed shape. The runtime `instanceof` check is identical for both forms — narrowing is purely at the type level. * **Python**, **Swift**, **Security Rules** — these SDK classes are not generic, so the emitted type is identical to the bare form. The schema-level validation that `model` resolves still runs. Zod self-references (e.g. `NoteLink.next: DocumentReference`) are emitted **without** the generic in Zod to avoid `TS2456 Type alias circularly references itself` on the `z.infer`-derived type. Pure `generate-ts` output is unaffected and emits the narrowed self-reference. Cross-model references narrow on both targets. ```yaml definition.yml theme={null} Author: model: document path: authors/{authorId} type: type: object fields: name: { type: string } Book: model: document path: books/{bookId} type: type: object fields: title: { type: string } author: type: type: document-reference model: Author ``` ```ts models.ts theme={null} export interface Author { name: string; } export interface Book { title: string; author: firestore.DocumentReference; } ``` ```python models.py theme={null} class Author(TypesyncModel): name: str class Book(TypesyncModel): title: str author: firestore.DocumentReference # not narrowed; Python SDK class is not generic ``` ```swift models.swift theme={null} struct Author: Codable { var name: String } struct Book: Codable { var title: String var author: DocumentReference // not narrowed; iOS SDK class is not generic } ``` ## `literal` Represents a literal type. Literal types are not supported in Swift. Typesync currently compiles literal types to the type of the literal value in Swift. ```yaml definition.yml theme={null} MeaningOfLife: model: alias type: type: literal value: 42 ``` ```ts models.ts theme={null} export type MeaningOfLife = 42; ``` ```swift models.swift theme={null} typealias MeaningOfLife = Int ``` ```python models.py theme={null} import typing MeaningOfLife = typing.Literal[42] ``` ```javascript firestore.rules theme={null} function isValidMeaningOfLife(data) { return data == 42; } ``` ## `enum` Represents an enum value. ```yaml definition.yml theme={null} UserRole: model: alias docs: Represents a user's role within a project. type: type: enum members: - label: Owner value: owner - label: Admin value: admin - label: Member value: member ``` ```ts models.ts theme={null} export type UserRole = 'owner' | 'admin' | 'member'; ``` ```swift models.swift theme={null} enum UserRole: String, Codable { case Owner = "owner" case Admin = "admin" case Member = "member" } ``` ```python models.py theme={null} import enum class UserRole(enum.Enum): Owner = "owner" Admin = "admin" Member = "member" ``` ```javascript firestore.rules theme={null} function isValidUserRole(data) { return data == 'owner' || data == 'admin' || data == 'member'; } ``` ## `tuple` Represents a tuple value. ```yaml definition.yml theme={null} Example: model: alias type: type: tuple elements: - string - boolean - int ``` ```ts models.ts theme={null} export type Example = [string, boolean, number]; ``` ```swift models.swift theme={null} typealias Example = (String, Bool, Int) ``` ```python models.py theme={null} Example = tuple[str, bool, int] ``` ```javascript firestore.rules theme={null} function isValidExample(data) { return ((data is list) && (data[0] is string) && (data[1] is bool) && (data[2] is int)); } ``` ## `list` Represents a list of items. ```yaml definition.yml theme={null} Example: model: alias type: type: list elementType: string ``` ```ts models.ts theme={null} export type Example = string[]; ``` ```swift models.swift theme={null} typealias Example = [String] ``` ```python models.py theme={null} Example = typing.List[str] ``` ```javascript firestore.rules theme={null} function isValidExample(data) { return (data is list); } ``` ## `map` Represents a mapping from arbitrary strings to values of any type. ```yaml definition.yml theme={null} Example: model: alias type: type: map valueType: int ``` ```ts models.ts theme={null} export type Example = Record; ``` ```swift models.swift theme={null} typealias Example = [String: Int] ``` ```python models.py theme={null} import typing Example = typing.Dict[str, int] ``` ```javascript firestore.rules theme={null} function isValidExample(data) { return (data is map); } ``` ## `object` Represents an object with known fields. ```yaml definition.yml theme={null} Example: model: alias type: type: object fields: name: type: string completed: type: boolean github_url: type: string optional: true ``` ```ts models.ts theme={null} export type Example = { name: string; completed: boolean; github_url?: string; }; ``` ```swift models.swift theme={null} struct Example: Codable { var name: String var completed: Bool var githubUrl: String? private enum CodingKeys: String, CodingKey { case name case completed case githubUrl = "github_url" } } ``` ```python models.py theme={null} # ... class Example(TypesyncModel): name: str completed: bool github_url: typing.Union[TypesyncUndefined, str] = UNDEFINED # ... ``` ```javascript firestore.rules theme={null} function isValidExample(data) { return ( (data is map) && (data.keys().hasOnly(['name', 'completed', 'github_url'])) && (data.name is string) && (data.completed is bool) && ((data.github_url is string) || !('github_url' in data)) ); } ``` ### Swift-specific options Use `swift.name` on an object field to override only the generated Swift property name. The Firestore field name stays the same. ```yaml theme={null} Example: model: alias type: type: object fields: class: type: string swift: name: userClass ``` ```swift theme={null} struct Example: Codable { var userClass: String private enum CodingKeys: String, CodingKey { case userClass = "class" } } ``` ## `union` Represents a union of multiple types. Typesync supports two types of unions: *simple union* and *discriminated union*. Both are defined in the same way using `variants`, except a discriminated union definition has a `discriminant` key and requires every variant to be of `object` (or `alias` resolving to `object`) type. **Simple Union Example** ```yaml definition.yml theme={null} Path: model: alias type: type: union variants: - string - type: list elementType: string ``` ```ts models.ts theme={null} export type Path = string | string[]; ``` ```swift models.swift theme={null} enum Example: Codable { case variant1(String) case variant2([String]) private enum CodingKeys: String, CodingKey { case variant1 case variant2 } init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() if let variant1 = try? container.decode(String.self) { self = .variant1(variant1) } else if let variant2 = try? container.decode([String].self) { self = .variant2(variant2) } else { throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Failed to decode ExampleSimpleUnion value.")) } } func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() switch self { case .variant1(let val): try container.encode(val) case .variant2(let val): try container.encode(val) } } } ``` ```python models.py theme={null} Path = typing.Union[str, typing.List[str]] ``` ```javascript firestore.rules theme={null} function isValidPath(data) { return ((data is string) || (data is list)); } ``` **Discriminated Union Example** ```yaml definition.yml theme={null} Cat: model: alias type: type: object fields: type: type: type: literal value: cat name: type: string lives_left: type: int Dog: model: alias type: type: object fields: type: type: type: literal value: dog name: type: string breed: type: string Pet: model: alias type: type: union discriminant: type variants: - Cat - Dog ``` ```ts models.ts theme={null} export type Cat = { type: 'cat'; name: string; lives_left: number; }; export type Dog = { type: 'dog'; name: string; breed: string; }; export type Pet = Cat | Dog; ``` ```swift models.swift theme={null} struct Cat: Codable { private(set) var type: String = "cat" var name: String var livesLeft: Int private enum CodingKeys: String, CodingKey { case type case name case livesLeft = "lives_left" } } struct Dog: Codable { private(set) var type: String = "dog" var name: String var breed: String } enum Pet: Codable { case cat(Cat) case dog(Dog) private enum CodingKeys: String, CodingKey { case type } enum PetType: String, Codable { case cat case dog } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) let type = try container.decode(PetType.self, forKey: .type) switch type { case .cat: self = .cat(try Cat(from: decoder)) case .dog: self = .dog(try Dog(from: decoder)) } } func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) switch self { case .cat(let obj): try container.encode(PetType.cat.rawValue, forKey: .type) try obj.encode(to: encoder) case .dog(let obj): try container.encode(PetType.dog.rawValue, forKey: .type) try obj.encode(to: encoder) } } } ``` ```python models.py theme={null} import typing import pydantic from typing_extensions import Annotated class Cat(TypesyncModel): type: typing.Literal["cat"] name: str lives_left: int class Dog(TypesyncModel): type: typing.Literal["dog"] name: str breed: str Pet = Annotated[typing.Union[Cat, Dog], pydantic.Field(discriminator='type')] ``` ```javascript firestore.rules theme={null} function isValidCat(data) { return ( (data is map) && (data.keys().hasOnly(['type', 'name', 'lives_left'])) && (data.type == 'cat') && (data.name is string) && (data.lives_left is int) ); } function isValidDog(data) { return ( (data is map) && (data.keys().hasOnly(['type', 'name', 'breed'])) && (data.type == 'dog') && (data.name is string) && (data.breed is string) ); } function isValidPet(data) { return (isValidCat(data) || isValidDog(data)); } ``` ## `alias` Represents an alias of another type. ```yaml definition.yml theme={null} User: model: alias type: type: object fields: name_first: type: string name_last: type: string WorkspaceMember: model: alias type: User ``` ```ts models.ts theme={null} export type User = { name_first: string; name_last: string; }; export type WorkspaceMember = User; ``` ```swift models.swift theme={null} struct User: Codable { var nameFirst: String var nameLast: String private enum CodingKeys: String, CodingKey { case nameFirst = "name_first" case nameLast = "name_last" } } typealias WorkspaceMember = User ``` ```python models.py theme={null} class User(TypesyncModel): name_first: str name_last: str WorkspaceMember = User ``` ```javascript firestore.rules theme={null} function isValidUser(data) { return ( (data is map) && (data.keys().hasOnly(['name_first', 'name_last'])) && (data.name_first is string) && (data.name_last is string) ); } function isValidWorkspaceMember(data) { return isValidUser(data); } ``` # Upgrading Source: https://docs.typesync.org/upgrading Upgrading your Typesync version is an important step to ensure you benefit from the latest features, bug fixes, and improvements. Until we reach our v1 release, breaking changes may occur between minor versions (e.g. when upgrading from v0.6 to v0.7). Here's how to manage upgrades smoothly: Always review the [changelog](https://github.com/kafkas/typesync/blob/main/CHANGELOG.md) for new features and breaking changes before upgrading. This will help you anticipate and prepare for any necessary adjustments. Update the JSON schema version in each schema definition file. This is a cheap way to quickly check if your current definition would be compatible with a new Typesync CLI version. For example, if you're planning to upgrade to 0.6.3, update the schema URL to `https://schema.typesync.org/v0.6.json`. If you notice any syntax errors (marked in red in most IDEs) after this update, it's likely you'll need to make some adjustments post-upgrade. For more information, see [Autocomplete/Intellisense](schema/definition#autcomplete-intellisense). Install the latest version of the Typesync CLI. ```bash Global theme={null} npm install -g typesync-cli@latest ``` ```bash Local theme={null} npm install typesync-cli@latest ``` Run `typesync --version` to check the version you're currently on. Validate your schema definition with the CLI. This will definitively confirm whether your current definition is compatible with the new CLI version. ```bash theme={null} typesync validate --definition ``` Thoroughly test the generated type definitions. Ensure your application builds with the new definitions and consider implementing automated tests to verify runtime behavior. If you encounter any issues or need further assistance while upgrading, please contact us on [Discord](https://discord.gg/Hb2HW98DvF).