Skip to content

Getting Started

From an empty directory to generating code from your first schema.

This guide takes you from an empty directory to generating code from your first schema. It assumes you can run a terminal; no prior knowledge of OpenSchema is required.

1. Install

OpenSchema runs on Bun. From the project directory:

bun install

You can run the CLI directly with Bun:

bun run src/cli/index.ts --help

To get a standalone binary you can drop into CI (no Bun required at runtime):

bun build src/cli/index.ts --compile --outfile openschema
./openschema --help

The rest of this guide writes openschema for brevity. Substitute bun run src/cli/index.ts if you have not built the binary.

2. Write your first schema

Create a file product.schema:

namespace catalog

/// A sellable product in the catalog.
model Product {
  @primaryKey @default(gen_uuid())
  1 id: uuid

  2 name: string

  @minLength(1)
  3 sku: string

  @minValue(0)
  4 priceCents: i64

  5 description: string?
  6 tags:        [string]
}

A few things to notice — each is explained fully in the Language Reference:

  • namespace catalog groups everything in the file under a name. Types are referred to elsewhere as catalog.Product.
  • model Product { ... } defines a structured type.
  • Every field starts with a number (1, 2, 3...). This is the field's ordinal — its permanent identity. Numbers may have gaps and need not be in order, but each must be unique within the model.
  • @primaryKey, @minValue(0), @format(...) are decorators — metadata that guides code generation and validation.
  • string? is a nullable field (the ?). [string] is a list of strings.

3. Validate it

openschema parse product.schema

This checks the syntax and prints a summary. If you made a typo, you get a precise error with a line and column:

Parse error at 4:14: Expected field name (identifier) (got ":" ":")

4. Generate code

Pick a target and an output directory:

openschema gen product.schema --target ts --out ./generated

./generated/schema.ts:

export interface Product {
  id: string;
  name: string;
  sku: string;
  priceCents: number;
  description?: string | null;
  tags: string[];
}

Try the other targets — the same source file drives all of them:

openschema gen product.schema --target sql         --out ./generated
openschema gen product.schema --target go          --out ./generated
openschema gen product.schema --target json-schema --out ./generated
openschema gen product.schema --target graphql     --out ./generated

See Code Generation for what each target produces and how decorators influence the output.

5. The day-two workflow: don't break consumers

Once other teams depend on your schema, you want to know before you ship whether a change is safe. OpenSchema diffs two versions of a schema and tells you exactly what changed and whether it breaks anyone:

openschema check product.v1.schema product.v2.schema --mode backward
  • Exit code 0 and a green check: the change is safe.
  • Exit code 1: a breaking change, with an explanation of why.

This is designed to run in CI as a gate on schema changes. See Compatibility Checking.

Where to go next