Mizzle ORM
A MongoDB ORM with exceptional developer experience, built for TypeScript.

Features
- Perfect Type Inference - S+ tier TypeScript support with zero
any types
- Flexible Relations - EMBED (denormalized), LOOKUP (virtual joins), and REFERENCE strategies
- Auto-updating Embeds - Optional
keepFresh mode keeps embedded data synchronized
- Intuitive API - Clean, modern syntax with excellent IntelliSense
- Context Support - Built-in multi-tenancy and auth context handling
- Transaction Support - First-class transaction API
- Zero Runtime Overhead - Compile-time type checking with minimal runtime cost
Installation
npm install @mizzle-dev/orm mongodb
pnpm add @mizzle-dev/orm mongodb
yarn add @mizzle-dev/orm mongodb
Requirements: Node.js 18+ and MongoDB 5.0+
Quick Start
import { mizzle, defineSchema, mongoCollection } from '@mizzle-dev/orm';
import { string, objectId, date } from '@mizzle-dev/orm';
import { lookup } from '@mizzle-dev/orm';
const users = mongoCollection('users', {
name: string(),
email: string(),
createdAt: date(),
});
const posts = mongoCollection(
'posts',
{
title: string(),
content: string(),
authorId: objectId(),
createdAt: date(),
},
{
relations: {
author: lookup(users, {
localField: 'authorId',
foreignField: '_id',
one: true,
}),
},
}
);
const schema = defineSchema({ users, posts });
const db = await mizzle({
uri: 'mongodb://localhost:27017',
dbName: 'myapp',
schema,
});
const user = await db().users.create({
name: 'Alice',
email: 'alice@example.com',
createdAt: new Date(),
});
const post = await db().posts.create({
title: 'Hello Mizzle!',
content: 'My first post',
authorId: user._id,
createdAt: new Date(),
});
const posts = await db().posts.findMany(
{},
{
include: { author: true },
}
);
posts[0].title;
posts[0].author?.name;
posts[0].author?.email;
Core Concepts
Relations
Mizzle supports three relation strategies:
1. EMBED Relations (Recommended)
Denormalize data for lightning-fast reads with optional auto-updates:
import { embed } from '@mizzle-dev/orm';
const posts = mongoCollection('posts', {
title: string(),
authorId: objectId(),
}, {
relations: {
author: embed(users, {
forward: {
from: 'authorId',
fields: ['name', 'email'],
},
keepFresh: true,
}),
},
});
const post = await db().posts.create({
title: 'Hello World',
authorId: userId,
});
console.log(post.author.name);
Benefits:
- Fast reads (no joins)
- Simple queries
- Optional auto-updates with
keepFresh
- Perfect for read-heavy workloads
2. LOOKUP Relations (Virtual Joins)
Query-time joins using MongoDB $lookup:
import { lookup } from '@mizzle-dev/orm';
author: lookup(users, {
localField: 'authorId',
foreignField: '_id',
one: true,
})
Benefits:
- Always fresh data
- Less storage
- Best for frequently-changing data
3. REFERENCE Relations (Validation)
Validate referential integrity:
import { reference } from '@mizzle-dev/orm';
author: reference(users, {
localField: 'authorId',
foreignField: '_id',
})
Context & Multi-tenancy
Pass context for auth and multi-tenancy:
const userPosts = await db({
user: { id: userId, role: 'admin' },
tenantId: 'acme-corp'
}).posts.findMany({});
const allPosts = await db().posts.findMany({});
Transactions
Built-in transaction support:
await db.tx({}, async (txDb) => {
const user = await txDb().users.create({ name: 'Bob' });
const post = await txDb().posts.create({
title: 'New Post',
authorId: user._id
});
});
Advanced Features
Auto-updating Embeds
Keep embedded data fresh automatically:
author: embed(users, {
forward: {
from: 'authorId',
fields: ['name', 'avatar']
},
keepFresh: true,
})
Manual Refresh
Refresh embeds on-demand:
const posts = await db().posts.findMany(
{ status: 'published' },
{ refreshEmbeds: ['author'] }
);
await db().posts.refreshEmbeds('author', {
filter: { updatedAt: { $lt: yesterday } },
batchSize: 100,
});
Nested Includes
Unlimited depth with perfect type inference:
const posts = await db().posts.findMany({}, {
include: {
author: {
include: {
organization: true
}
},
comments: {
include: {
user: true
}
}
}
});
posts[0].author?.organization?.name
posts[0].comments[0]?.user?.email
When to Use Each Relation Type
| Blog post authors | EMBED + keepFresh | Fast reads, occasional updates |
| E-commerce orders | EMBED (no auto-update) | Historical snapshot |
| Real-time stock prices | LOOKUP | Always need latest data |
| User permissions | LOOKUP | Changes frequently |
| Tag clouds | EMBED + keepFresh | Fast display, rare changes |
Examples
Check out the examples directory for comprehensive demonstrations:
Documentation
API Overview
Collections
const user = await db().users.create({ name: 'Alice' });
const users = await db().users.createMany([...]);
const user = await db().users.findOne({ email: 'alice@example.com' });
const users = await db().users.findMany({ active: true });
const users = await db().users.findMany({}, { include: { posts: true } });
await db().users.updateOne({ _id: userId }, { name: 'Alice Updated' });
await db().users.updateMany({ active: false }, { deleted: true });
await db().users.deleteOne({ _id: userId });
await db().users.deleteMany({ deleted: true });
const result = await db().users.aggregate([...]);
const collection = db().users.collection;
Database Instance
db.schema
db.client
db.tx
db.close()
TypeScript Support
Mizzle provides exceptional TypeScript support:
- Zero
any types in your queries
- Perfect inference for nested includes
- Compile-time safety for all operations
- Full IntelliSense support
- Type-safe filters and projections
Performance
Read Performance:
- EMBED: ~50-100ms for 1000 documents
- LOOKUP: ~200-500ms for 1000 documents
Recommendation: Use EMBED for read-heavy workloads, LOOKUP for write-heavy or when data changes frequently.
Contributing
Contributions are welcome! Please check out our GitHub repository.
- Fork the repository
- Create your feature branch
- Commit your changes
- Push to the branch
- Open a Pull Request
License
MIT © Mizzle Dev
Links
Built with love for the MongoDB + TypeScript community