Usage
Usage
Basic Conversion
To convert a Zod schema into a Mongoose schema, use the toMongooseSchema function. This is the main entry point for using zod-mongoose in your backend application.
import { z } from 'zod/v4';
import { toMongooseSchema } from '@nullix/zod-mongoose';
import mongoose from 'mongoose';
// Define a Zod schema
const UserZodSchema = z.object({
username: z.string().min(3),
email: z.string().email(),
age: z.number().optional(),
});
// Convert to Mongoose Schema
const UserSchema = toMongooseSchema(UserZodSchema);
// Create a Mongoose Model
const UserModel = mongoose.model('User', UserSchema);
Passing Mongoose Options
The second parameter of toMongooseSchema allows you to specify standard Mongoose schema options, such as timestamps, collection, and versionKey.
const mongooseSchema = toMongooseSchema(UserZodSchema, {
timestamps: true,
collection: 'users',
});
Extending Schemas
zod-mongoose makes it easy to extend your schemas with Mongoose plugins or custom logic using hooks.
Using Mongoose Plugins
You can apply standard Mongoose plugins directly during the conversion process.
import mongooseLeanVirtuals from 'mongoose-lean-virtuals';
const mongooseSchema = toMongooseSchema(zodSchema, {
plugins: [mongooseLeanVirtuals]
});
Using Hooks
The schema:created hook allows you to modify the mongoose.Schema instance immediately after it is created.
import { hooks } from '@nullix/zod-mongoose';
hooks.hook('schema:created', ({ schema, zodSchema }) => {
// Add a virtual field to all schemas that have a 'title' field
if ('title' in zodSchema.shape) {
schema.virtual('slug').get(function() {
return this.title.toLowerCase().replace(/ /g, '-');
});
}
});
Advanced Type Handling
zod-mongoose provides specialized helpers for Mongoose-specific types.
ObjectIds and Buffers
Use zObjectId() and zBuffer() for fields that map to Mongoose ObjectId and Buffer types.
import { zObjectId, zBuffer } from '@nullix/zod-mongoose';
const ProductSchema = z.object({
_id: zObjectId(), // Managed by Mongoose unless { includeId: true } is passed
category: zObjectId({ ref: 'Category' }),
imageData: zBuffer(),
});
Populated Fields
For fields that can be either an ObjectId (unpopulated) or a full object (populated), use zPopulated.
import { zPopulated } from '@nullix/zod-mongoose';
const PostSchema = z.object({
author: zPopulated('User', UserZodSchema),
});
Adding Mongoose Metadata
Use withMongoose to add Mongoose-specific options like unique, index, or default.
import { withMongoose } from '@nullix/zod-mongoose';
const UserZodSchema = z.object({
email: withMongoose(z.string().email(), {
unique: true,
index: true
}),
});
Isomorphic Support (Frontend Mode)
In modern applications, you often want to share your Zod schemas between your backend and your frontend. To do this, enable "frontend mode" on your client.
import { setFrontendMode } from '@nullix/zod-mongoose';
// On the frontend, enable frontend mode
setFrontendMode(true);
// Now schemas using zObjectId() will fall back to string validation
// and zBuffer() will fall back to Uint8Array, without requiring Mongoose.
Using with Nuxt 4 & Nitro
zod-mongoose is optimized for Nuxt 4. You can use your Zod schemas directly with readValidatedBody in your Nitro server routes.
// server/api/users.post.ts
import { UserZodSchema } from '~/schemas/user';
export default defineEventHandler(async (event) => {
const body = await readValidatedBody(event, UserZodSchema.parse);
// body is now fully typed and validated by Zod
const user = await UserModel.create(body);
return user;
});