npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@migrex/zod

v1.0.0-alpha.1

Published

Zod schema plugin for migrex

Readme

@migrex/zod

Zod schema integration for migrex - use Zod schemas as versioned schemas in your migration graph.

Features

  • Zod integration - Wrap Zod schemas for use with migrex
  • Type inference - Full TypeScript type inference from Zod schemas
  • Field schemas - Create validated field schemas for the preservation stash
  • Deprecation metadata - Mark schema versions as deprecated

Installation

npm install @migrex/zod @migrex/core zod@^3.24.0

Note: @migrex/zod requires Zod v3.x. Zod v4.x is not yet supported due to breaking API changes.

Usage

Basic Usage

import { z } from 'zod';
import { fromZod } from '@migrex/zod';
import { createMigrationGraph, semverStrategy } from '@migrex/core';

// Define Zod schemas
const UserV1Schema = z.object({
  name: z.string(),
  email: z.string().email(),
});

const UserV2Schema = z.object({
  firstName: z.string(),
  lastName: z.string(),
  email: z.string().email(),
});

// Create versioned schemas
const schemaV1 = fromZod('1.0.0', UserV1Schema);
const schemaV2 = fromZod('2.0.0', UserV2Schema);

// Register with migration graph
const graph = createMigrationGraph({
  id: 'user-schema',
  versionStrategy: semverStrategy,
});

graph.registerSchema(schemaV1);
graph.registerSchema(schemaV2);

Type Inference

Use InferZodSchema to extract types from your Zod schemas:

import { z } from 'zod';
import type { InferZodSchema } from '@migrex/zod';

const UserSchema = z.object({
  name: z.string(),
  age: z.number(),
});

type User = InferZodSchema<typeof UserSchema>;
// { name: string; age: number }

Field Schemas for Preservation

import { z } from 'zod';
import { createFieldSchema } from '@migrex/zod';

const avatarSchema = createFieldSchema(
  z.string().url(),
  { description: 'User avatar URL' }
);

// Use in migration context
const migration = {
  fromVersion: '1.0.0',
  toVersion: '2.0.0',
  up: (data, ctx) => {
    ctx.preserve('avatar', data.avatar, {
      fieldSchema: avatarSchema,
    });
    return { ...data, avatar: undefined };
  },
  down: (data, ctx) => {
    const avatar = ctx.consume('avatar');
    return { ...data, avatar: avatar?.value };
  },
};

Custom Validation

Add business logic validation that runs after Zod parsing:

const schemaV1 = fromZod('1.0.0', UserV1Schema, {
  validate: (data) => {
    if (data.email.endsWith('@spam.com')) {
      return {
        success: false,
        errors: [{ path: ['email'], message: 'Spam emails not allowed' }],
      };
    }
    return { success: true, data };
  },
});

Deprecation Metadata

const schemaV1 = fromZod('1.0.0', UserV1Schema, {
  deprecated: {
    since: '2.0.0',
    successor: '2.0.0',
    deadline: '2025-06-01',
    message: 'Please upgrade to v2.0.0 for improved name handling',
  },
  releaseDate: '2024-01-01',
});

Schema Extension

The extendZodSchema and omitFromZodSchema utilities help reduce duplication when creating multiple schema versions:

extendZodSchema

Extend a base schema with new fields while updating the version literal:

import { z } from 'zod';
import { extendZodSchema, fromZod } from '@migrex/zod';

const ConfigV1 = z.object({
  version: z.literal('1.0.0'),
  name: z.string(),
  port: z.number(),
});

// Extend to v1.1.0 with new logLevel field
const ConfigV1_1 = extendZodSchema(ConfigV1, '1.1.0', {
  logLevel: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
});
// ConfigV1_1 now has: version: '1.1.0', name, port, logLevel

const schemaV1 = fromZod('1.0.0', ConfigV1);
const schemaV1_1 = fromZod('1.1.0', ConfigV1_1);

omitFromZodSchema

Remove deprecated fields when creating new schema versions:

import { omitFromZodSchema, fromZod } from '@migrex/zod';

const V1 = z.object({
  version: z.literal('1.0.0'),
  name: z.string(),
  deprecatedField: z.string(),
});

const V2 = omitFromZodSchema(V1, '2.0.0', ['deprecatedField']);
// V2 has: version: '2.0.0', name (deprecatedField removed)

const schemaV2 = fromZod('2.0.0', V2);

Combining omit and extend

// Remove old field and add new ones
const V2WithoutOld = omitFromZodSchema(V1, '2.0.0', ['oldName']);
const V2 = extendZodSchema(V2WithoutOld, '2.0.0', {
  firstName: z.string(),
  lastName: z.string(),
});

API Reference

fromZod(version, zodSchema, options?)

Create a versioned schema from a Zod schema.

| Parameter | Type | Description | |-----------|------|-------------| | version | string | Version identifier | | zodSchema | ZodType<T> | Zod schema to wrap | | options | FromZodOptions<T> | Optional configuration |

Options

| Option | Type | Description | |--------|------|-------------| | validate | (data: T) => ValidationResult<T> | Additional validation function | | deprecated | DeprecationInfo | Deprecation metadata | | releaseDate | string | Release date of this version |

createFieldSchema(zodSchema, options?)

Create a field schema for use with the preservation stash.

| Parameter | Type | Description | |-----------|------|-------------| | zodSchema | ZodType<T> | Zod schema to wrap | | options | { description?: string } | Optional description |

InferZodSchema<T>

Type helper to extract the inferred type from a Zod schema.

type User = InferZodSchema<typeof UserSchema>;

Complete Example

import { z } from 'zod';
import { fromZod, createFieldSchema, type InferZodSchema } from '@migrex/zod';
import { createMigrationGraph, semverStrategy, type ReversibleMigration } from '@migrex/core';

// Define schemas
const UserV1 = z.object({
  name: z.string(),
  avatar: z.string().url().optional(),
});

const UserV2 = z.object({
  firstName: z.string(),
  lastName: z.string(),
});

type UserV1Type = InferZodSchema<typeof UserV1>;
type UserV2Type = InferZodSchema<typeof UserV2>;

// Create versioned schemas
const schemaV1 = fromZod('1.0.0', UserV1);
const schemaV2 = fromZod('2.0.0', UserV2);

// Field schema for preserved fields
const avatarFieldSchema = createFieldSchema(z.string().url());

// Define migration
const migration: ReversibleMigration<UserV1Type, UserV2Type> = {
  fromVersion: '1.0.0',
  toVersion: '2.0.0',
  up: (data, ctx) => {
    if (data.avatar) {
      ctx.preserve('avatar', data.avatar, { fieldSchema: avatarFieldSchema });
    }
    const [firstName, ...rest] = data.name.split(' ');
    return { firstName, lastName: rest.join(' ') || '' };
  },
  down: (data, ctx) => {
    const avatar = ctx.consume('avatar');
    return {
      name: `${data.firstName} ${data.lastName}`.trim(),
      avatar: avatar?.value as string | undefined,
    };
  },
};

// Build graph
const graph = createMigrationGraph({
  id: 'user-schema',
  versionStrategy: semverStrategy,
});

graph.registerSchema(schemaV1);
graph.registerSchema(schemaV2);
graph.registerMigration(migration);

// Use
const result = graph.migrate({ name: 'John Doe', avatar: 'https://example.com/avatar.png' }, '1.0.0', '2.0.0');
console.log(result.data); // { firstName: 'John', lastName: 'Doe' }

Development

# Build the package
pnpm build

# Run tests
pnpm test

# Build types
pnpm build:types

# Update API report
pnpm api:update

License

UNLICENSED