FAQ
Frequently asked questions about Takeout architecture and design decisions
Common questions about architecture and design decisions.
Why not use drizzle-zero to auto-generate Zero schema?
drizzle-zero is a package that auto-generates Zero schemas from Drizzle ORM definitions. Takeout intentionally doesn’t use it.
Co-location with model logic
Zero schemas live in src/data/models/ alongside mutations, permissions, and related logic. This keeps all model concerns together:
src/data/models/post.ts
├── schema (Zero table definition)
├── permissions (who can access)
└── mutations (create, update, delete)
When you open a model file, you see everything about that entity in one place.
Explicit control
Manually defining Zero schema gives precise control over what syncs to clients:
- Exclude columns from sync (sensitive data, server-only fields)
- Use different types than Drizzle (Zero has its own type system)
- Evolve schemas independently
Fewer dependencies
No need to wait for drizzle-zero updates when Zero or Drizzle release breaking changes. One less package to maintain compatibility with.
Easier to swap Drizzle
If you ever want to switch ORMs (Kysely, Prisma, raw SQL), the Zero schema remains untouched. Drizzle is only used for migrations and server-side queries.
Clarity
Two explicit schema files make it obvious what’s in the database vs what syncs to clients. Useful when onboarding new developers.
Keeping schemas in sync
The schemas rarely drift. When adding a new table:
- Add to Drizzle schema (
src/database/schema-public.ts) - Add to Zero model (
src/data/models/) - Add relationships (
src/data/relationships.ts) - Run migrations
Changes to existing tables follow the same pattern. over-zero generate catches type mismatches at build time.
When drizzle-zero makes sense
drizzle-zero is a good choice if you:
- Want zero configuration
- Sync all columns to clients
- Prefer single source of truth over co-location
- Don’t mind the dependency
For Takeout, the co-location benefits outweigh the duplication cost.
Why separate Drizzle and Zero relationships?
Drizzle relationships use relations() from drizzle-orm. Zero relationships use a different format. Takeout defines Zero relationships separately in src/data/relationships.ts.
This separation allows:
- Different relationship names (Drizzle might use
author, Zero usesuser) - Subset of relationships for sync (not everything needs to sync)
- Cleaner model files (relationships are infrastructure, not domain logic)
Why over-zero instead of raw @rocicorp/zero?
over-zero adds three things:
- Queries as functions - Write plain functions, they become synced queries. No manual
SyncedQuerywrappers or validator boilerplate. - Mutations with CRUD - Pass schema + permissions to
mutations()and get auto-generated insert/update/delete/upsert that check permissions server-side. - Permission helpers -
where()creates composable conditions that only run server-side.can()checks them in mutations.usePermission()checks them in React.
The CLI generates glue code (types, synced queries with valibot validators, model aggregation) and enforces a clean src/data/ structure with models/, queries/, and generated/ directories.
Resources
Edit this page on GitHub.