Data

A real database, live in your browser, from schema to production.

A backend project, App or Game, comes with a complete data stack that runs in the browser. Each project gets the Orez Rust sync engine and Bedrock SQLite in one Web Worker. The Website template is frontend only and has no data stack.

You work with three things: a schema you author, generated outputs, and mutators that write data.

The schema you author

A project’s data model lives in a few files at the project root:

  • database/schema.ts holds your Drizzle tables.
  • database/relations.ts holds the relations between them.
  • database/drizzle-zero.config.ts lists which tables Zero syncs. A table has to be listed here to reach the client.

You edit these files directly. Changing Contrast’s own platform schema is a separate repo-level task, not part of building your app.

Generate and Migrate

Two Run menu actions turn your schema into a running database:

  • Run → Generate writes the generated outputs from your schema and data files: everything under data/generated/ and database/generated/init.sql. These are outputs. You don’t hand-edit them.
  • Run → Migrate compares the running database against your current schema, applies the supported changes, and asks for confirmation before anything destructive, like a drop that would lose data.

The reference for both, including the baseline they diff against, is on the data generation page. Run → Restart disposes and reboots the whole stack when you need a clean slate.

Inspecting data

The SQLite DevTools pane is a live window into the project’s database. Use Browse to read tables, Query to run read-only SELECT, WITH, and EXPLAIN statements, and Search to look across text columns. It is how you confirm a mutation actually wrote what you expected.

Writing data with mutators

Apps change data through mutators: functions that run three times. They run optimistically on the client, rebased on the client as other changes arrive, and authoritatively on the server. Because the same body runs in all three contexts, it has to be deterministic. Ids and timestamps come from the caller, never from Date.now() or a random id inside the body.

Client code reads synced data through named queries, not ad-hoc reads. An inline query on the client only sees the local cache and silently returns empty for rows nothing has synced. The full set of rules app authors need is on the mutators reference page.

The same stack in production

The Orez engine and on-zero application surface you run in the browser are the ones you deploy. When you publish, your schema, named queries, mutators, permissions, auth, seed, and API routes ship without a rewrite. See the Deploy pane for how a backend goes live.

Ready?

Create a web, iOS, and Android app in minutes with agents working alongside you.