Validate Documents
Validate Documents
toMongooseSchema() maps supported Zod checks to Mongoose options. It also runs the Zod schema in a post('validate') hook by default, so refinements that Mongoose cannot represent still reject invalid documents.
Add a refinement
import mongoose from 'mongoose';
import {z} from 'zod/v4';
import {toMongooseSchema} from '@nullix/zod-mongoose';
const BookingZodSchema = z.object({
startsAt: z.date(),
endsAt: z.date(),
}).refine(({startsAt, endsAt}) => endsAt > startsAt, {
message: 'End must be after start',
path: ['endsAt'],
});
const Booking = mongoose.model('Booking', toMongooseSchema(BookingZodSchema));
const booking = new Booking({
startsAt: new Date('2026-01-02'),
endsAt: new Date('2026-01-01'),
});
await booking.validate(); // Rejects the document; no database connection is needed.
The hook parses document.toObject() after Mongoose validation. It checks Zod refinements, but it does not copy Zod's parsed output back into the Mongoose document. If you use .transform() to normalize input, parse that input before constructing or updating a Mongoose document.
For z.strictObject(), z.looseObject(), and .catchall(), Mongoose must also keep or reject unknown fields while constructing the document. See Object Modes and Unknown Keys for their storage behavior and the difference between document saves and query updates.
import {z} from 'zod/v4';
const NameInput = z.object({name: z.string().trim().toLowerCase()});
const normalized = NameInput.parse({name: ' ADA '});
// normalized.name === 'ada'; pass normalized to your Mongoose model.
Disable the extra Zod validation
const mongooseSchema = toMongooseSchema(BookingZodSchema, {
validateBeforeSave: false,
});
This option skips the package's Zod validation hook. Mongoose's own validation still runs. You can also set validateBeforeSave: false in top-level withMongoose metadata. See Core Functions for the option signature.