A TypeScript data layer that keeps schemas, types, validation, and SQL in sync. The codebase was written entirely by LLMs.
Project status: pre-1.0 (
1.0.0-beta.2). zmdb is authored and reviewed by LLMs under the oversight of a single maintainer. The public API may change without notice before 1.0.0, there is no release cadence or support commitment yet, and there is no LTS. It requires Node 26+ and TypeScript 7.0+, and it has not been exercised in production. Use it where you can afford to follow a moving API; the anti-patterns page is the fastest way to find out whether its design suits you. Twenty-one packages aresupportedand six areprovisional; support tiers states what each version number promises and what evidence stands behind it.
┌─────────────────────────────────────────────────────────────┐
│ Define once. Everything derives. Zero boilerplate. │
└─────────────────────────────────────────────────────────────┘
- Why zmdb — what it replaces, and the four-metadata-systems problem it exists to remove. Names Zod, Typia, Drizzle, MikroORM and
@nestjs/swaggerrather than arguing against a straw man. - Anti-patterns — the design's sharp edges, and the quickest way to decide zmdb is not for you.
- Already using an ORM: Drizzle · Prisma · TypeORM · Sequelize · MikroORM. Each guide maps the concepts, not just the API names.
- FAQ — licensing under MPL-2.0, what LLM authorship means for the code you would depend on, and the questions that come up before adoption.
- Getting help — one maintainer, GitHub Issues, no support commitment before 1.0.
Install @zmdb/core to define a schema, generate its migration, validate requests and persist typed records behind an HTTP controller. SQLite is included. Start with the
quick start, then follow the blog API tutorial and generated client.
The product uses the same schema through validation, SQL, repositories and HTTP. The runnable server journey demonstrates a real HTTP request, persistence and a selected background worker under one application lifecycle.
Choose a database, client framework, job provider or transport when the application needs it. The generated package reference owns package identities, installation commands, peer requirements and support evidence. The integration guide connects the generated HTTP client to the selected framework. Advanced dependency boundaries are explained in the runtime foundation and tooling guides.
The workspace publishes 27 packages across 182 export-map entry points. Vitest discovers runtime tests from the workspace. The compatibility inventory covers 504 of 742 upstream API suites and explains why the other 238 are out of scope. Documentation contains 289 pages and 1,289 classified TypeScript/TSX fences; the documentation inventory records their statuses, compilation modes and GraphQL exclusions.
Create a formatter-clean SQLite project with the packaged CLI:
yarn dlx -p @zmdb/cli@1.0.0-beta.2 zmdb new project blog
cd blog
yarn install
yarn check
yarn build
yarn startThe generated project includes a strict TypeScript config, AOT build adapter, health route and behavioural test, and zmdb.config.ts. Add a table declaration, then generate and apply its reviewed
migration through the same executable:
yarn zmdb new schema user
yarn zmdb generate --name initial
yarn zmdb migrateimport { DatabaseSync } from 'node:sqlite';
import { defineRepository, schemaOf, type HasDefault, type PrimaryKey, type Serial, type Sql, type Table } from '@zmdb/core';
import { sqliteDriver } from '@zmdb/core/sqlite';
// A table is a TypeScript type. Tags carry the database details that TypeScript
// cannot express on its own, and disappear from the emitted JavaScript.
export interface User extends Table<'users'> {
id: number & Sql<'integer'> & Serial & PrimaryKey;
email: string & Sql<'text'>;
role: ('admin' | 'user') & HasDefault;
}
// Create a typed repository without a subclass.
const users = defineRepository(schemaOf<User>(), sqliteDriver(new DatabaseSync('app.db')));
await users.create({ email: 'a@b.com' }); // validated vs CreateDTO<S>
const admins = await users.find({ role: 'admin' }); // typed WhereDTO<S>
const page = await users.list({ page: { limit: 20 } }); // ListResult<Entity<S>>The default import is the lazy, logic-free application surface. Focused APIs remain available from @zmdb/core/schema, @zmdb/core/sql, @zmdb/core/validator, @zmdb/core/orm, @zmdb/core/web,
@zmdb/core/migrations, @zmdb/core/compiler, and @zmdb/core/testing; optional integrations are installed separately.
schemaOf<T>() is resolved at build time because TypeScript erases type arguments before the program runs. Set up the build plugin, or run the code generator, as described in
AOT setup. Calling untransformed code fails with a clear error instead of returning an empty schema.
You can also install individual packages or subclass BaseRepository from @zmdb/core/orm. Continue through the full quick start and
blog API tutorial.
An explicit @zmdb/web/contract declaration drives runtime routing, OpenAPI, and generated client code. yarn zmdb client generate emits OpenAPI JSON and a typed TypeScript client as sibling
outputs; --check rejects stale committed bytes and --watch follows the compiled contract dependency set.
The generated module imports only the dependency-free @zmdb/client runtime, accepts caller-supplied authentication and cancellation, and runs in browser or Node bundles. The
generated-client guide covers the complete journey and the separate low-level manual @zmdb/client path.
The documentation site covers schemas, CRUD, relations, transactions, migrations, query building, validation, serialization, the web framework, and the remaining roadmap.
Some familiar ORM features conflict with zmdb's no-proxy, ahead-of-time design. The anti-patterns guide explains why identity maps, automatic unit-of-work flushes, lazy relation proxies, and JIT mappers are not part of the project.
See also ARCHITECTURE.md and the COOKBOOK.md.
Read ARCHITECTURE.md for the policy-generated package graph and admission workflow, PUBLISHING.md for the current executable publication workflow,
scripts/release/SPEC.md for the frozen release-group and compatibility contract, support tiers for what each version number
promises, and COOKBOOK.md for practical examples.
The benchmark suite uses the upstream projects and their normal workloads. The ORM comparison runs the 13 drizzle-benchmarks routes against PostgreSQL 18.6 and replays them with k6. zmdb supports every route, including joins, aggregates, and full-text search.
The September 9 replay uses matching projections, responses and shared indexes. Median-throughput repetitions measured zmdb at 11,719 requests/s with p95/p99 of 39.23/49.51 ms, Kysely at 10,643 requests/s with 44.65/53.46 ms, and Drizzle at 5,830 requests/s with 97.30/120.04 ms. All nine runs had zero HTTP failures. These short, co-located runs use unprepared statements; the dashboard retains every repetition and its throughput range. Earlier projection-mismatched results cannot establish a before/after speedup.
The validation comparison uses typescript-runtime-type-benchmarks. The runtime and generated AOT participants cover strict parsing and
loose/strict assertions. Both omit parseSafe: its upstream contract requires removing unknown properties, which these APIs retain. The latest run compares them with ts-runtypes and
ts-runtime-checks; this fixed-input throughput benchmark does not measure individual-call p95/p99.
The refresh includes two selected peers per category. Unsupported cases and measurement limits are listed explicitly; the selected comparisons do not establish an ecosystem-wide rank.
See the dashboard for current results, benchmarks/RESULTS.md for archived captures and benchmarks/harness/ for reproduction instructions.
📊 Interactive dashboard (charts + Node/Bun/Deno tabs, like the upstream sites): https://ambasta.github.io/zmdb/benchmarks/
- Node.js 26+
- TypeScript 7.0+
Mozilla Public License 2.0 (MPL-2.0). See LICENSE.
What you build with zmdb is yours. MPL is file-level copyleft: it covers zmdb's own source files, and your application is a Larger Work you may license however you like — closed, commercial, unpublished. There is no network clause of any kind, so operating a service on zmdb carries no obligation. If you modify zmdb itself and ship it to someone, that person is entitled to the modified zmdb source.
Code that zmdb's compiler, client generator, migration tooling, and scaffolding write into your project is explicitly not covered — see the Generated Output Exception.