Examples
See Monkko in action with these practical examples that showcase its key features.
Pre-v1 Notice: Monkko is currently in pre-v1 development. The API may change between releases. We recommend pinning to specific versions in production environments.
Basic Schema Definition
Here’s what working with Monkko looks like:
1. Define Your Schema
// schemas/User.monkko.ts
import { defineSchema, fields } from '@monkko/orm'
export const User = defineSchema({
name: "User",
db: "myapp",
collection: "users",
fields: {
name: fields.string({ required: true }),
email: fields.string({ required: true, unique: true }),
age: fields.number({ optional: true }),
organisation: fields.objectId({ required: false, ref: "Organisation" })
createdAt: fields.date({ default: () => new Date() })
}
});
2. Generate Types & Validation
# Run the CLI to generate everything you need
pnpm monkko generate
This automatically creates:
- ✅ TypeScript types for your models
- ✅ Zod schemas for validation
- ✅ Fully typed query builders
3. Use Your Fully-Typed Models
import { userModel } from './models/User'
// ✨ Everything is typed with generics!
const users = await userModel
.find({ name: { $regex: /john/i } })
.populate("organisation")
.toJSON(); // ← Handles serialization automatically
// TypeScript knows the exact shape:
// users: Array<{
// name: string;
// email: string;
// age?: number;
// organisation: Organisation; // ← Populated!
// createdAt: Date;
// }>
💡 Info: Monkko uses generics for type safety throughout your query chain. The
toJSON()
function automatically handles serialization, so you don’t need to worry about manual type casting or serialization!
Multi-Database Architecture
Unlike other ORMs that assume a single database, Monkko is designed for MongoDB clusters where you have multiple databases. Each model connects to the correct database:
// Each model connects to the right database
export const User = defineSchema({
name: "User",
db: "users", // ← Connects to the users database
collection: "users",
fields: { /* ... */ }
});
export const AnalyticsEvent = defineSchema({
name: "AnalyticsEvent",
db: "analytics", // ← Different database, same cluster
collection: "events",
fields: { /* ... */ }
});
Type Safety Examples
Stop casting to any
and losing type safety. Monkko uses generics to preserve types through your entire query chain:
// Without populate - use toJSON() for proper serialization
const user = await userModel.findById(userId).toJSON();
// user.organisation → ObjectId (string)
// With populate - types automatically update
const user = await userModel
.findById(userId)
.populate("organisation")
.toJSON();
// user.organisation → Organisation (full object!)
// Multiple populates - all handled with generics
const post = await postModel
.findById(postId)
.populate("author")
.populate("comments.user")
.toJSON();
// TypeScript knows exactly what's populated!
🔥 Pro Tip: Always use
.toJSON()
at the end of your queries. It handles serialization automatically and ensures you get the correct TypeScript types without manual casting!