Zod-first MongoDB

Zog

A small persistence boundary for teams that want MongoDB to feel like Zod, without teaching every schema about storage history.

Read the docs
pnpm add @mp-lb/zog
Schema
Zod stays the source of truth
Read path
Mongo document to parsed value
Write path
Parsed value to canonical _id
Legacy
Normalize old storage shapes before parse
API surface

A collection that parses.

Zog keeps the repository API close to MongoDB while giving each model a typed, parsed boundary.

const userModel = createModel("users", userSchema, {
  primaryKey: "id",
  collectionName: "users",
  legacyCollectionNames: ["user_accounts"],
  indexes: [uniqueIndex({ email: 1 })],
});

const db = defineDb([userModel] as const, {
  mongoClient,
  databaseName: "app",
});

const user = await db.users.findById("user_1");
Storage boundary
01

Mongo documents enter through Zod

Every repository read is parsed before application code sees it, so broken storage shape fails at the boundary.

02

Application ids stay application ids

Keep your model in terms of id while Zog stores the same value canonically as Mongo _id.

03

Indexes belong next to the model

Declare, diff, and sync Mongo indexes from the same place you define collection shape.

04

Legacy shape has a home

Collection renames, old primary keys, and storage normalization stay outside your current schema.