Playground
Api

Plugins and Hooks

Extend zod-mongoose using Mongoose plugins and a powerful hook system.

Plugins and Hooks

@nullix/zod-mongoose is designed to be highly extensible. You can apply standard Mongoose plugins and use a granular hook system to customize the conversion process.

Mongoose Plugins

You can pass Mongoose plugins directly to toMongooseSchema. This is the recommended way to extend your schemas with third-party or custom Mongoose plugins.

import { z } from 'zod/v4';
import { toMongooseSchema } from '@nullix/zod-mongoose';
import mongooseLeanVirtuals from 'mongoose-lean-virtuals';

const zodSchema = z.object({
  title: z.string(),
});

// Apply plugins during conversion
const mongooseSchema = toMongooseSchema(zodSchema, {
  plugins: [mongooseLeanVirtuals]
});

// The resulting schema now has the plugin applied
const Post = mongoose.model('Post', mongooseSchema);
const doc = await Post.findOne().lean({ virtuals: true });

Hook System

@nullix/zod-mongoose uses unjs/hookable to provide an extensible conversion process. Developers can register hooks to modify the Mongoose definition at any point of the conversion.

Registering Hooks

import { hooks } from '@nullix/zod-mongoose';

// Modify every string field to be uppercase at the Mongoose level
hooks.hook('converter:node', (context) => {
  if (context.type === 'string') {
    context.mongooseProp.uppercase = true;
  }
});

Advanced Hook: schema:created

Use the schema:created hook 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, '-');
    });
  }
});

Available Hooks

The following hook points are available:

  • converter:before: Called before starting the conversion.
  • converter:start: Called at the start of each extractMongooseDef call (recursive).
  • converter:unwrapped: Called after unwrapping a Zod schema and extracting metadata.
  • converter:node: Called for each Zod type node being processed.
  • converter:after: Called after a node's conversion is complete.
  • schema:object:before: Called before processing a z.object().
  • schema:object:field: Called for each field in a z.object().
  • schema:object:after: Called after processing a z.object().
  • schema:array:before: Called before processing an array-like type (z.array(), z.set(), z.tuple()).
  • schema:array:after: Called after processing an array-like type.
  • schema:record:before: Called before processing a record/map type (z.record(), z.map()).
  • schema:record:after: Called after processing a record/map type.
  • schema:union:before: Called before processing a z.union() or z.discriminatedUnion().
  • schema:union:after: Called after processing a union.
  • validation:mappers: Called after mapping Zod validations to Mongoose options.
  • schema:created: Called after a mongoose.Schema instance is created.