Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.typesync.org/llms.txt

Use this file to discover all available pages before exploring further.

Typesync is an open-source schema management toolkit for 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.
models.yml
# yaml-language-server: $schema=https://schema.typesync.org/v0.15.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:
typesync generate-ts --target firebase@10 --definition models.yml # ... other options
The generator commands produce the following files:
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;
}
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.
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<User>;
const userDocRef = doc(usersColRef, 'adam');
const userSnap = await getDoc(userDocRef);
const user = userSnap.data(); // is a User object

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.