Single schema declaration
Type-safe MongoDB ODM on top of official driver
MongoDB with Types!
Mongster keeps the MongoDB driver's mental model intact, then layers runtime validation, typed aggregation, typed populate, hooks, and transaction-scoped models on top.
npm i mongodb mongsterTyped aggregations builders
Populate with a single trip
import { , } from "mongster";
const = .({
: .().(1).(100),
: .().(),
}).();
export const = ("users", );
const = .({
: .().(1).(200),
: .().(false),
: .().(() => ),
}).();
export const = ("todos", );
Strict enough to matter
Schema-first w/o hiding MongoDB
Validation, refs, default values, timestamps, and index metadata stay in one definition.
Official driver underneath
No fake relational mental model. Just MongoDB, sharpened for TypeScript.
Why Mongster ?
Features that you need
Capabilities that feel most different in practice:
The ones that remove duplicated types, keep MongoDB expressive,
and still give you guardrails
One schema, many outputs
M.schema drives runtime validation, stored document types, input types, refs, timestamps, and index metadata from one place.
Read sectionTyped aggregation builder
Group, project, unwind, and lookup without dropping back to loose result shapes every time a pipeline changes.
Read sectionTransaction-scoped models
Use ctx.use(Model) inside a transaction and keep the same mental model while sessions are wired automatically.
Read sectionTyped populate
Declare "relations" with objectId().ref(() => Model), then populate with typed selection paths instead of guesswork.
Read sectionHooks without magic fog
Schema and model hooks stay explicit, sequential, and useful for auditing, normalization, and derived writes.
Read sectionSingle source of truth
One schema fans out into the parts that usually drift
Inspired by some of the best schema-centric TypeScript libraries, but tuned for MongoDB. The same definition powers runtime validation, document types, input types, refs, and indexes.
import { } from "mongodb";
import { , } from "mongster";
const = .({
: .().(1),
});
const = ("users", );
const = .({
: .().(1).(200),
: .().(false),
: .().(() => ),
: .().(),
}).();
type = M.<typeof >;
type = M.<typeof >;
const = ("todos", );
const : = {
: "Ship docs",
: "ship-docs",
: new ("64f8e6a25e6f0a1c2d3b4e5f"),
};
await .();Single source of truth
Reject bad writes before they hit MongoDB
Rules, defaults, refs, and timestamps stay in the schema, so invalid payloads fail before they become messy data.
This is the contract your handlers feel immediately: fewer parallel validators, less drift.
Fits your stack
Built for modern TypeScript apps
Use Mongster where MongoDB teams already live: API servers, TanStack Start, Next.js, or lean edge apps that still want strong type guarantees.
Official MongoDB driver core
Keep MongoDB semantics instead of hiding them under a second abstraction stack.
Open guideHono and API edges
Schema-first models and runtime validation fit lightweight APIs without ceremony.
Open guideTanStack Start apps
Use Mongster in server functions while keeping return shapes serializable and typed.
Open guideNext.js apps
Drop models into server-side code, keep MongoDB close, and still get disciplined TS ergonomics.
Open guideGet moving fast
From installation to first typed query in 3 moves
Landing pages should reduce hesitation. These are the first three actions most visitors want before they commit to reading the full docs.
Terminal
Install on top of the real driver
npm i mongodb mongsterMongster wraps the official MongoDB driver instead of replacing it with a separate persistence model.
Schema
Define one schema
import { M, model } from "mongster";
const todoSchema = M.schema({
title: M.string().min(1).max(200), // [!code highlight]
completed: M.boolean().default(false), // [!code highlight]
slug: M.string().uniqueIndex(), // [!code highlight]
}).withTimestamps(); // [!code highlight]
export const TodoModel = model("todos", todoSchema);Add validation rules, refs, defaults, and indexes once, then let types and runtime checks follow.
Query
Query with Mongo semantics
import { } from "./models";
const = await .({ : false })
.(["title", "createdAt"]) // [!code highlight]
.({ : -1 })
.(10);
// prettier-ignore
const = await .({ : true })
.("ownerId", { // [!code highlight]
: ["name", "email"], // [!code highlight]
});
const firstOwner = [0].;Keep Mongo-style filters, add typed projections, populate, aggregation, hooks, and transaction helpers.
Start strict. Stay fast.
Build on MongoDB w/o giving up type integrity.
Read the quick start, inspect the API surface, or drop Mongster into your next TypeScript app and let one schema hold the line.
