Skip to content

What is Monch?

Monch is a lightweight MongoDB ODM (Object Document Mapper) for TypeScript that combines the power of Zod validation with MongoDB operations. It provides a type-safe, developer-friendly way to work with MongoDB while ensuring data integrity through schema validation.

Why Monch?

The Problem

Working with MongoDB in TypeScript often involves:

  • Manual type definitions that can drift from actual data
  • No validation at the database boundary
  • Tedious BSON serialization for frameworks like Next.js
  • Boilerplate for common patterns like timestamps and pagination

The Solution

Monch addresses these issues with:

  • Zod Schemas as Source of Truth - Your schema defines both validation rules and TypeScript types
  • Automatic Validation - Documents are validated before insert, with partial validation on updates
  • Built-in Serialization - Convert BSON types to JSON-safe values with a single .serialize() call
  • Zero Configuration - Set MONGODB_URI and start coding

Core Principles

1. Validation at the Boundary

Monch validates data at the database boundary—when documents enter MongoDB. This catches errors early and ensures data consistency:

typescript
// Invalid data is rejected before reaching MongoDB
await Users.insertOne({
  name: '',  // Throws: String must contain at least 1 character
  email: 'not-an-email',  // Throws: Invalid email
});

2. Type Safety Throughout

Types flow from your Zod schema through queries to serialized output:

typescript
const Users = collection({
  schema: {
    _id: field.id(),
    name: field.string(),
    email: field.email(),
  },
  timestamps: true,
});

// TypeScript knows the shape
const user = await Users.findOne({ email: 'alice@example.com' });
// user: { _id: ObjectId, name: string, email: string, createdAt: Date, updatedAt: Date } | null

const serialized = user?.serialize();
// serialized: { _id: string, name: string, email: string, createdAt: string, updatedAt: string }

3. Progressive Enhancement

Monch stays out of your way. Use as much or as little as you need:

typescript
// Basic: Just schema and name
const Simple = collection({
  name: 'simple',
  schema: { _id: field.id(), value: field.string() },
});

// Full-featured: Timestamps, hooks, methods, indexes
const Advanced = collection({
  name: 'advanced',
  schema: { /* ... */ },
  timestamps: true,
  indexes: [{ key: { email: 1 }, unique: true }],
  hooks: { beforeInsert: (doc) => ({ ...doc, normalized: true }) },
  methods: { fullName: (doc) => `${doc.first} ${doc.last}` },
});

Comparison

FeatureMonchMongoosePrisma
TypeScript-firstPartial
Zod validation
Zero config
Serialization helpers
Schema file required
Code generation
Bundle size~15KB~800KB~2MB

Next Steps

Released under the MIT License.