← Back to Home

Documentation

SchemaShift is a TypeScript CLI tool that migrates schemas between validation libraries using AST-based transformations. It preserves code structure, formatting, and comments while converting your schemas.

Getting Started

Installation

Install SchemaShift globally via npm:

npm install -g schemashift-cli

Or use npx to run without installing:

npx schemashift --help

Quick Start

Analyze your project to see what schemas you have:

schemashift analyze ./src

Preview migration changes with dry-run:

schemashift migrate ./src --from yup --to zod --dry-run

Run the migration:

schemashift migrate ./src --from yup --to zod
Tip

Always run with --dry-run first to preview changes before modifying files.

analyze

Scan your project and detect schema definitions across all supported libraries.

schemashift analyze <path> [options]
Option Description
--json Output results as JSON
-v, --verbose Show detailed schema information
--detailed Full stats with complexity scoring and readiness Individual+
--readiness <path> Migration readiness report, e.g. "yup->zod" Individual+
--complexity Per-schema complexity scores Individual+
--behavioral <migration> Behavioral difference warnings, e.g. "yup->zod" Free
--bundle <migration> Bundle size estimation, e.g. "zod->valibot" Individual+
--performance <migration> Performance impact analysis, e.g. "zod-v3->v4" Individual+
--dedup Detect duplicate type definitions Individual+

Example output:

Schema Analysis

Total files: 47
Files with schemas: 12
Total schemas: 34

Schemas by library:

  yup: 28
  zod: 6

migrate

Transform schemas from one library to another.

schemashift migrate <path> --from <library> --to <library> [options]
Option Description
-f, --from Source library (yup, joi, io-ts, zod-v3)
-t, --to Target library (zod, v4, valibot)
-d, --dry-run Preview changes without writing files
-v, --verbose Show detailed transformation info
-c, --config Path to config file
--report <format> Generate report (json, html, csv)
--report-output Report output path
--chain <path> Chain migration, e.g. "yup->zod->valibot" Pro+
--cross-file Resolve cross-file schema imports Pro+
--compat-check Run compatibility check before migration Pro+
--git-branch Create git branch for changes
--git-commit Auto-commit changes
--no-backup Skip backup creation
--ci CI mode (exit code 1 on failure)
--fail-on-warnings Exit 1 if any warnings Team
--max-risk-score <n> Exit 1 if file exceeds risk score (0-100) Team
--scaffold-tests Generate validation tests after migration Pro+
--audit Enable migration audit logging Team
--preset <name> Use a migration preset Individual+
--output-diff <file> Export unified diff to file (use - for stdout) Free
--canary <percent> Migrate only N% of files, simplest first Pro+
--compliance-report <format> Generate compliance report (soc2, hipaa) Team

Examples:

# Basic migration
schemashift migrate ./src --from yup --to zod

# With HTML report
schemashift migrate ./src --from joi --to zod --report html

# Chain migration: Yup → Zod → Valibot
schemashift migrate ./src --chain yup->zod->valibot

# Cross-file with compatibility check
schemashift migrate ./src --from yup --to zod --cross-file --compat-check

# CI mode with risk threshold
schemashift migrate ./src --from yup --to zod --ci --fail-on-warnings --max-risk-score 50

watch

Watch files and automatically migrate on save. Requires Pro or Team license.

schemashift watch <path> --from <library> --to <library>
Option Description
-f, --from Source library
-t, --to Target library
-c, --config Path to config file

Press Ctrl+C to stop watching.

rollback

Restore files from a backup created during migration.

schemashift rollback [backupId] [options]
Option Description
-l, --list List available backups
--clean Remove old backups (keeps last 5)

Examples:

# List all backups
schemashift rollback --list

# Restore most recent backup
schemashift rollback

# Restore specific backup
schemashift rollback backup-1706123456789

# Clean old backups
schemashift rollback --clean

license

Manage your license activation.

schemashift license [options]
Option Description
-a, --activate <key> Activate a license key
-d, --deactivate Deactivate current license
-s, --status Show license status

Examples:

# Check current license status
schemashift license

# Activate a license
schemashift license --activate SCHEMASHIFT_PRO_xxxx-xxxx-xxxx

# Deactivate to move to another device
schemashift license --deactivate

pricing

Display pricing information and available tier features.

schemashift pricing

Shows a summary of all tiers, their prices, supported migrations, and key features.

init

Create a .schemashiftrc.json configuration file.

schemashift init [options]
Option Description
-f, --force Overwrite existing config

compat

Check schema library compatibility before migration. Pro+

schemashift compat <path> [--json]

Detects installed library versions from package.json and reports known version-specific issues. For example, Zod v3's .errors property was renamed to .issues in v4, and z.record() now requires a key type argument.

# Check compatibility
schemashift compat ./src

# Machine-readable output
schemashift compat ./src --json

governance

Run schema governance checks against configurable rules. Team

schemashift governance <path> [options]
Option Description
--json Output results as JSON
--fix Auto-fix fixable violations (no-any-schemas, require-descriptions, require-max-length, naming-convention)
--fix-dry-run Preview auto-fixes without applying changes
-c, --config Path to config file

Enforces naming conventions, complexity limits, required validations, and more. See Governance Configuration for setup.

# Run governance checks
schemashift governance ./src

# Auto-fix violations
schemashift governance ./src --fix

# Preview auto-fixes without applying
schemashift governance ./src --fix-dry-run

# With custom config
schemashift governance ./src -c .schemashiftrc.json

graph

Export schema dependency graph in DOT or Mermaid format. Pro+

schemashift graph <path> [options]
Option Description
--format <dot|mermaid> Output format (default: mermaid)
--output <file> Write to file instead of stdout
--filter <library> Show only schemas from a specific library
--highlight-circular Highlight circular dependencies
--color Color-code nodes by library

Examples:

# Export Mermaid diagram to stdout
schemashift graph ./src

# Export DOT format to file
schemashift graph ./src --format dot --output schema-deps.dot

# Highlight circular dependencies with colors
schemashift graph ./src --highlight-circular --color

presets

List available migration presets for common scenarios. Individual+

schemashift presets [options]
Option Description
--json Output as JSON
--category <cat> Filter by category

Built-in Presets

Preset Description
react-hook-form-yup-to-zod React Hook Form project migrating from Yup to Zod, including resolver updates
trpc-zod-v3-to-v4 tRPC project upgrading Zod from v3 to v4
express-joi-to-zod Express.js project migrating Joi validation to Zod
nextjs-form-migration Next.js form validation migration
monorepo-staged-migration Phased monorepo migration with topological ordering

Use a preset with the migrate command:

schemashift migrate ./src --preset react-hook-form-yup-to-zod

approvals

Manage migration approval workflows for shared codebases. Team

schemashift approvals [path] [options]
Option Description
--create Create a new migration request
--approve <id> Approve a pending request
--reject <id> Reject a pending request
--list List all requests
--status <status> Filter by status (pending, approved, rejected)
-f, --from Source library (for --create)
-t, --to Target library (for --create)
--reviewer <name> Reviewer name
--reason <reason> Decision reason
--json Output as JSON

Examples:

# Create a migration request
schemashift approvals ./src --create --from yup --to zod

# List pending requests
schemashift approvals --list --status pending

# Approve a request
schemashift approvals --approve req-1706123456 --reviewer "Jane" --reason "LGTM"

# Reject a request
schemashift approvals --reject req-1706123456 --reviewer "Jane" --reason "Needs tests first"
Tip

Approval requests are stored in .schemashift/pending/ as JSON files. Integrate with code review workflows by committing these files to your repository.

doctor

Diagnose project health and suggest migrations. Free

schemashift doctor [path] [options]
Option Description
--json Output as JSON

The doctor command performs several health checks:

Example output:

schemashift doctor

 package.json found
! Zod v3.22.0 detected — v4 available
 No form library issues
i Suggestion: schemashift migrate . -f zod-v3 -t v4

verify

Contract testing — verify migrated schemas match originals. Pro+

schemashift verify <path> -f <library> -t <library> [options]
Option Description
-f, --from Source schema library
-t, --to Target schema library
--samples <count> Number of test samples to generate (default: 50)
--json Output as JSON

The verify command:

  1. Extracts schema names from source files (supports Zod, Yup, Joi, Valibot patterns)
  2. Generates test samples (valid + invalid boundary data) based on schema structure
  3. Validates samples through both source and target schemas
  4. Reports parity score with detailed mismatch information
schemashift verify ./src -f yup -t zod --samples 100

compare

Side-by-side schema comparison showing how source maps to target. Individual+

schemashift compare <path> -f <library> -t <library> [--json]

hooks

Manage pre-commit hook integration for governance checks. Pro+

schemashift hooks <install|uninstall|status>
Subcommand Description
install Detect husky/lint-staged and add governance check hook
uninstall Remove SchemaShift git hooks
status Show current hook configuration

policy

Policy-as-code management for schema governance. Team

schemashift policy <init|check|list> [path]
Subcommand Description
init Generate a policy file from governance templates
check <path> Run governance checks with active policies
list Show available governance templates with categories

Examples:

# Initialize policies from templates
schemashift policy init

# Check project against policies
schemashift policy check ./src

# List available governance templates
schemashift policy list

Yup → Zod

Available in: Free, Individual, Pro, Team

Transforms Yup schemas to Zod equivalents:

// Before (Yup)
import * as yup from 'yup';

const userSchema = yup.object({
  name: yup.string().required(),
  email: yup.string().email().required(),
  age: yup.number().positive().optional(),
});

// After (Zod)
import { z } from 'zod';

const userSchema = z.object({
  name: z.string(),
  email: z.string().email(),
  age: z.number().positive().optional(),
});

Mapping Reference

Yup Zod
yup.string() z.string()
yup.number() z.number()
yup.boolean() z.boolean()
yup.date() z.date()
yup.array() z.array()
yup.object() z.object()
.required() (default in Zod)
.optional() .optional()
.nullable() .nullable()
.min(n) .min(n)
.max(n) .max(n)
.email() .email()
.url() .url()
.oneOf([...]) z.enum([...])
.mixed() z.unknown()
.isTrue() z.literal(true)
.isFalse() z.literal(false)
Note

Yup's .test() custom validators become Zod's .refine(). Review these manually for correctness.

Joi → Zod

Available in: Free, Individual, Pro, Team

// Before (Joi)
import Joi from 'joi';

const schema = Joi.object({
  username: Joi.string().alphanum().min(3).max(30).required(),
  email: Joi.string().email(),
  website: Joi.string().uri(),
});

// After (Zod)
import { z } from 'zod';

const schema = z.object({
  username: z.string().regex(/^[a-zA-Z0-9]+$/).min(3).max(30),
  email: z.string().email().optional(),
  website: z.string().url().optional(),
});

Mapping Reference

Joi Zod
Joi.string() z.string()
Joi.number() z.number()
Joi.boolean() z.boolean()
Joi.date() z.date()
Joi.array() z.array()
Joi.object() z.object()
.required() (default in Zod)
.optional() .optional()
.allow(null) .nullable()
.alphanum() .regex(/^[a-zA-Z0-9]+$/)
.email() .email()
.uri() .url()
.valid(...) z.enum([...])
.any() z.unknown()
Note

Joi's .when() conditional validation requires manual conversion using .refine() or discriminated unions.

Zod v3 → v4

Available in: Individual, Pro, Team

Handles breaking changes between Zod v3 and v4:

// Before (Zod v3)
const schema = z.record(z.number());
const result = schema.safeParse(data);
if (!result.success) {
  console.log(result.error.errors);
}

// After (Zod v4)
const schema = z.record(z.string(), z.number());
const result = schema.safeParse(data);
if (!result.success) {
  console.log(result.error.issues);
}

Breaking Changes Handled

v3 v4 Action
z.record(valueSchema) z.record(z.string(), valueSchema) Auto-transformed
error.errors error.issues Auto-transformed
.merge(other) .extend(other.shape) Auto-transformed + warning
z.nativeEnum(X) z.enum(X) Auto-transformed + warning
.superRefine() .check() Auto-transformed
.strict() z.strictObject() Deprecation warning
.passthrough() z.looseObject() Deprecation warning
.pipe() .pipe() (stricter) Behavior warning
invalid_type_error / required_error Unified error param Auto-transformed
instanceof Error on ZodError ZodError no longer extends Error Runtime warning
.refine().transform() .transform() runs even if refine fails Runtime warning
.default().optional() .optional() is effectively a no-op Runtime warning
error.flatten() z.flattenError(error) Auto-transformed
error.format() z.treeifyError(error) Auto-transformed
schema._def.typeName schema._zod.def.typeName Auto-transformed
ctx.addIssue() in .superRefine() ctx.issues.push() in .check() Auto-transformed
.catch() + .optional() .catch() catches all issues, .optional() is no-op Runtime warning
ZodType, ZodSchema imports Moved to zod/v4/core Import warning
.strip() Removed (default behavior in v4) Auto-removed
z.preprocess(fn, schema) z.pipe(z.unknown(), z.transform(fn), schema) Auto-transformed

Zod v4 also delivers up to 14x faster parsing performance. See the Zod v4 changelog for the full list of changes.

io-ts → Zod

Available in: Pro, Team

// Before (io-ts)
import * as t from 'io-ts';

const User = t.type({
  name: t.string,
  age: t.number,
  email: t.union([t.string, t.undefined]),
});

// After (Zod)
import { z } from 'zod';

const User = z.object({
  name: z.string(),
  age: z.number(),
  email: z.string().optional(),
});
Manual Review Required

io-ts uses fp-ts patterns (Either, pipe) that don't translate directly. Review decode() calls and error handling after migration.

Zod ↔ Valibot

Available in: Pro, Team

Convert between Zod and Valibot schemas:

# Zod to Valibot
schemashift migrate ./src --from zod --to valibot

# Valibot to Zod
schemashift migrate ./src --from valibot --to zod

Key Mappings

Zod Valibot
z.string() v.string()
z.object({...}) v.object({...})
z.enum([...]) v.picklist([...])
.min(n) v.pipe(schema, v.minLength(n))
.optional() v.optional(schema)
.nullable() v.nullable(schema)
.refine(fn) v.check(fn)
.nanoid() v.pipe(schema, v.nanoid())
.base64() v.pipe(schema, v.base64())
.hexColor() v.pipe(schema, v.hexColor())
Note

Valibot uses a functional pipe-based API rather than method chaining. Complex Zod schemas with deep chaining may need manual adjustment after migration. Valibot v1 added many new validators (nanoid, base64, hexColor, isoWeek, and more) that are now supported.

Zod → Yup (Backward Migration)

Available in: Pro, Team

AST-based backward migration converting Zod schemas to Yup equivalents:

schemashift migrate ./src --from zod --to yup
// Before (Zod)
import { z } from 'zod';

const userSchema = z.object({
  name: z.string(),
  email: z.string().email(),
  age: z.number().positive().optional(),
});

// After (Yup)
import * as yup from 'yup';

const userSchema = yup.object({
  name: yup.string().required(),
  email: yup.string().email().required(),
  age: yup.number().positive().notRequired(),
});

Valibot → Zod (Backward Migration)

Available in: Pro, Team

Text-based backward migration converting Valibot schemas to Zod:

schemashift migrate ./src --from valibot --to zod
// Before (Valibot)
import * as v from 'valibot';

const productSchema = v.object({
  name: v.pipe(v.string(), v.minLength(1)),
  price: v.pipe(v.number(), v.minValue(0)),
  status: v.picklist(['active', 'archived']),
});

// After (Zod)
import { z } from 'zod';

const productSchema = z.object({
  name: z.string().min(1),
  price: z.number().min(0),
  status: z.enum(['active', 'archived']),
});

Zod ↔ ArkType

Pro+

Bidirectional migration between Zod and ArkType. ArkType uses a string-based syntax that is fundamentally different from Zod's fluent API.

ZodArkType
z.object({ name: z.string() })type({ name: "string" })
z.string().email()type("string.email")
z.number().integer()type("integer")
z.union([z.string(), z.number()])type("string | number")
z.array(z.string())type("string[]")
z.infer<typeof schema>Type<typeof schema>

Zod ↔ Superstruct

Pro+

Bidirectional migration between Zod and Superstruct. Superstruct uses bare function calls without a namespace prefix.

ZodSuperstruct
z.object({ name: z.string() })object({ name: string() })
z.string()string()
z.number()number()
z.enum(["a", "b"])enums(["a", "b"])
z.string().optional()optional(string())
z.number().int()integer()
z.infer<typeof schema>Infer<typeof schema>

io-ts → Effect Schema

Pro+

Migrate io-ts codecs to Effect Schema. This is the successor path for io-ts users since fp-ts merged into Effect.

io-tsEffect Schema
t.stringS.String
t.numberS.Number
t.booleanS.Boolean
t.type({ name: t.string })S.Struct({ name: S.String })
t.array(t.string)S.Array(S.String)
t.union([A, B])S.Union(A, B)
t.TypeOf<typeof schema>S.Schema.Type<typeof schema>

fp-ts imports are automatically rewritten to Effect equivalents (e.g., pipe from effect/Function).

Type Helper Migration

SchemaShift automatically converts type inference helpers when migrating between libraries:

Source Target
yup.InferType<typeof schema> z.infer<typeof schema>
Joi.extractType<typeof schema> z.infer<typeof schema>
t.TypeOf<typeof schema> z.infer<typeof schema>
t.OutputOf<typeof schema> z.output<typeof schema>
z.infer<typeof schema> v.InferOutput<typeof schema>
z.input<typeof schema> v.InferInput<typeof schema>

Form Library Compatibility

SchemaShift detects form library imports and warns you to update resolvers/adapters after migration:

Form Library Detected Imports Action Needed
react-hook-form react-hook-form, @hookform/resolvers/* Switch resolver (e.g. @hookform/resolvers/zod)
Formik formik Update validation adapter to match target library
Mantine Form @mantine/form Update zodResolver or equivalent for target library
Automatic Resolver Migration

Individual+ tiers include automatic form resolver migration: yupResolverzodResolver, joiResolverzodResolver, zodResolvervalibotResolver imports are rewritten automatically during migration. No manual import changes needed.

Config File

Create .schemashiftrc.json in your project root:

{
  "include": ["src/**/*.ts", "src/**/*.tsx"],
  "exclude": [
    "**/node_modules/**",
    "**/dist/**",
    "**/*.d.ts",
    "**/*.test.ts"
  ],
  "backup": {
    "enabled": true,
    "dir": ".schemashift-backup"
  },
  "git": {
    "enabled": false,
    "createBranch": true,
    "branchPrefix": "schemashift/",
    "autoCommit": false,
    "commitMessage": "chore: migrate schemas with SchemaShift"
  },
  "customRules": []
}

Options

Option Type Description
include string[] Glob patterns for files to include
exclude string[] Glob patterns for files to exclude
backup.enabled boolean Create backups before migration
backup.dir string Backup directory path
git.enabled boolean Enable git integration
git.createBranch boolean Create branch for changes
git.branchPrefix string Branch name prefix
git.autoCommit boolean Auto-commit after migration
git.commitMessage string Commit message template
customRules array Custom transformation rules

Custom Rules

Define custom transformation rules in your config:

{
  "customRules": [
    {
      "name": "company-validator",
      "match": "yup.string().companyId()",
      "replace": "z.string().regex(/^CMP-[0-9]+$/)"
    }
  ]
}

Governance Configuration

Configure schema governance rules in your config file (Team):

{
  "governance": {
    "rules": {
      "naming-convention": { "pattern": ".*Schema$" },
      "max-complexity": { "threshold": 80 },
      "no-any": {},
      "required-validations": {}
    },
    "failOnViolation": true
  }
}

Built-in rules:

Rule Description
naming-convention Schemas must match a regex pattern (default: .*Schema$)
max-complexity Reject schemas above a complexity score threshold
no-any Disallow z.any() and equivalents (severity: error)
required-validations String schemas must include .max() for length safety
Security

Regex patterns in governance rules (e.g., naming-convention) are protected against ReDoS attacks. Patterns longer than 500 characters are rejected, and invalid patterns fail safely without crashing the process.

Plugin Configuration

Load custom plugins from npm packages or local files (Team):

{
  "plugins": ["./my-plugin.js", "@my-org/schemashift-plugin"]
}

Plugins export a SchemaShiftPlugin interface with optional transform handlers and custom rules. See the GitHub repo for plugin development documentation.

Advanced Analysis

Analyze schema complexity and migration readiness (Individual+):

schemashift analyze ./src --detailed
schemashift analyze ./src --readiness yup->zod
schemashift analyze ./src --complexity --json

Complexity scoring considers chain length, nesting depth, and validation count. Scores are rated as low (0-25), medium (26-50), high (51-75), or critical (76-100).

Risk Scoring

Each migrated file receives a risk score based on warnings, errors, and manual review items (Individual+). Use --max-risk-score in CI to enforce quality thresholds:

schemashift migrate ./src --from yup --to zod --ci --max-risk-score 50

Export risk data for project tracking:

schemashift migrate ./src --from yup --to zod --report csv

Cross-File Resolution

Resolve schema imports across files and transform in dependency order (Pro+):

schemashift migrate ./src --from yup --to zod --cross-file

SchemaShift builds a dependency graph, detects circular dependencies, and applies transformations in topologically sorted order.

Chain Migrations

Perform multi-step migrations in a single command (Pro+):

schemashift migrate ./src --chain yup->zod->valibot

Each step validates intermediate output before proceeding. Combined reports include all steps. Use instead of --from / --to.

Ecosystem Detection

SchemaShift detects third-party packages in your project that may break or need updates during migration (Pro+):

When you run --compat-check, SchemaShift automatically scans your package.json for ecosystem dependencies and reports compatibility issues before migration begins.

Package Affected Migration Issue
drizzle-zod zod-v3 → v4 Needs v4-compatible version
@trpc/server v10 zod-v3 → v4 tRPC v10 expects Zod v3 types
zod-validation-error zod-v3 → v4 Must upgrade to v5.0.0+
@hookform/resolvers any → zod, zod-v3 → v4 Resolver version must match schema lib
zod-openapi zod-v3 → v4 Needs v4-compatible version
zod-prisma zod-v3 → v4 Generated schemas may need regeneration
formik yup → zod Must switch form adapter
@mantine/form yup → zod Must switch schema adapter
@asteasolutions/zod-to-openapi zod-v3 → v4 Needs v4-compatible version
trpc-ui zod-v3 → v4 Breaks with v4 schemas
# Run ecosystem detection as part of compat check
schemashift migrate ./src --from zod-v3 --to v4 --compat-check

# Or standalone compatibility check
schemashift compat ./src

Standard Schema

SchemaShift detects Standard Schema 1.0 compatible libraries in your project. This helps you understand interoperability options between schema libraries.

Compatible libraries include Zod v3.23+, Valibot v1+, ArkType v2+, @effect/schema, and TypeBox v0.34+. Detection is included in the analyze command output (FREE tier).

Form Resolver Migration

SchemaShift automatically rewrites form resolver imports during migration (Individual+):

Migration Before After
yup → zod import { yupResolver } from '@hookform/resolvers/yup' import { zodResolver } from '@hookform/resolvers/zod'
joi → zod import { joiResolver } from '@hookform/resolvers/joi' import { zodResolver } from '@hookform/resolvers/zod'
zod → valibot import { zodResolver } from '@hookform/resolvers/zod' import { valibotResolver } from '@hookform/resolvers/valibot'

For Formik and @mantine/form, TODO comments are added with guidance since those require manual adapter changes.

Complexity Estimation

Get pre-migration effort estimates before transforming any code (Individual+):

The complexity estimator analyzes your schema files and produces an effort level for each file: trivial, low, moderate, high, or extreme. It detects advanced patterns (branded types, recursive schemas, custom validators), performance risks, and provides risk area summaries.

Tip

Run complexity estimation before migration to identify files that may need manual review. Focus on "high" and "extreme" files first.

TODO Resolution Summary

After migration, SchemaShift scans all generated TODO(schemashift) comments and produces a categorized summary (Free):

Each category includes a resolution guide with specific steps to complete the migration.

Monorepo-Aware Migration

SchemaShift detects monorepo workspace configurations and suggests migration order (Pro+):

Note

Monorepo detection reads workspace globs from your root package.json. Ensure your workspace configuration is up to date before running detection.

Behavioral Warnings

Detect behavioral differences between schema libraries before migration (Free):

schemashift analyze ./src --behavioral yup->zod

Identifies coercion differences (e.g., Yup auto-coerces strings to numbers, Zod does not), validation order changes, and error format differences. Warnings are grouped by category with severity levels to help you prepare for migration.

Bundle Size Estimation

Estimate the bundle size impact of switching schema libraries (Individual+):

schemashift analyze ./src --bundle zod->valibot

Compares minified+gzipped library sizes and reports the estimated delta in kB and percentage. Useful for understanding the size impact before committing to a migration.

Performance Impact Analysis

Identify potential performance changes from your migration (Individual+):

schemashift analyze ./src --performance zod-v3->v4

Reports validation speed differences, parse vs safeParse overhead, and runtime behavior impacts. Warnings are severity-rated (error, warning, info) with detailed explanations.

Type Deduplication Detection

Find structurally similar schema definitions across your codebase (Individual+):

schemashift analyze ./src --dedup

Identifies duplicate schemas with confidence scores. Clean up redundant definitions before or after migration to reduce maintenance burden.

Dead Schema Detection

Find schema definitions that are never referenced elsewhere in your codebase (Individual+):

schemashift analyze ./src --dedup

Scans for variable declarations that use schema library patterns (z., yup., Joi., etc.) and checks if those variables are referenced in other files or elsewhere in the same file. Exported schemas are considered "used" and won't be flagged. Reports the total schema count and a list of unused schemas with file paths and line numbers.

Tip

Run dead schema detection after migration to clean up schemas that were only needed by the source library. Removing unused code reduces maintenance burden and improves build times.

Import Deduplication

Detect duplicate import declarations from the same module within files (Free):

After migration, files may end up with multiple import statements from the same module — for example, two import { ... } from 'zod' lines. The import deduplicator detects these and suggests merged imports for cleaner code.

// Before (duplicate imports)
import { z } from 'zod';
import { ZodError } from 'zod';

// Suggested merge
import { z, ZodError } from 'zod';

Test Scaffolding

Generate validation test files after migration (Pro+):

schemashift migrate ./src --from yup --to zod --scaffold-tests

Creates test stubs for each migrated schema in .schemashift/tests/. Each test file includes basic validation checks to verify the migration preserved behavior.

Audit Logging

Record detailed migration history for compliance (Team):

schemashift migrate ./src --from yup --to zod --audit

Logs each file transform with timestamps, success/failure status, and warning counts. The audit log is persisted to .schemashift/audit-log.json for enterprise compliance and traceability. Enhanced with metadata collection (git commit, branch, CI provider), JSON/CSV export, and date range filtering.

Data Integrity

All persisted state files (audit logs, approval requests, incremental migration state) are validated with runtime type guards on read. Corrupted or tampered files are safely rejected instead of causing runtime errors.

Schema Drift Detection

Detect when schemas diverge from a saved baseline (Team):

The drift detector takes a snapshot of your schema state (file paths, content hashes, schema names) and saves it to .schemashift/schema-snapshot.json. Later, compare the current state against the snapshot to detect added, removed, and modified schema files.

Useful for compliance auditing, CI drift checks, and tracking schema evolution over time.

Governance Templates

Built-in governance rule templates for common policies (Team):

Access templates programmatically via getGovernanceTemplate(name), getGovernanceTemplateNames(), and getGovernanceTemplatesByCategory().

CI Reporting (SARIF/JUnit)

Machine-readable output formats for CI/CD pipelines (Pro+):

SARIF — Static Analysis Results Interchange Format for GitHub Code Scanning. Categorizes warnings into manual-review, behavioral-change, deprecated-pattern, and ecosystem-compatibility.

JUnit — XML test report format for CI systems (Jenkins, GitLab CI, etc.). Creates test suites per file with test cases per transform result.

Exit codes: 0 = success, 1 = failure, 2 = warnings (when --fail-on-warnings is enabled).

A reusable GitHub Action is also available at .github/actions/schemashift/action.yml for easy CI/CD pipeline integration. See GitHub Action below.

GitHub Action

A reusable GitHub Action for CI/CD pipeline integration (Pro+):

# .github/workflows/schema-migration.yml
name: Schema Migration
on: [push]
jobs:
  migrate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/schemashift
        with:
          command: migrate
          path: ./src
          from: yup
          to: zod
          license-key: ${{ secrets.SCHEMASHIFT_LICENSE_KEY }}
          extra-args: "--ci --report json"

Action Inputs

Input Description Default
command CLI command to run (migrate, analyze, governance) migrate
path Path to scan ./src
from Source library
to Target library
license-key SchemaShift license key
extra-args Additional CLI flags

Action Outputs

Output Description
exit-code CLI exit code (0=success, 1=failure, 2=warnings)
report-path Path to generated report file (if --report used)

Webhook Notifications

Send migration event notifications to external services (Team):

Configure webhooks in your .schemashiftrc.json to receive notifications when migration events occur:

{
  "webhooks": [
    {
      "url": "https://hooks.slack.com/services/T00/B00/xxxx",
      "events": ["migration_completed", "migration_failed"],
      "secret": "your-hmac-secret"
    },
    {
      "url": "https://your-api.com/webhooks/schemashift",
      "events": ["governance_violation", "drift_detected"],
      "headers": { "Authorization": "Bearer token" }
    }
  ]
}

Event Types

Webhook Type Formatting

Add a type field to automatically format payloads for specific platforms:

{
  "webhooks": [
    {
      "url": "https://hooks.slack.com/services/T00/B00/xxxx",
      "type": "slack",
      "events": ["migration_completed"]
    },
    {
      "url": "https://outlook.office.com/webhook/...",
      "type": "teams"
    }
  ]
}

Webhook Options

Webhooks are signed with HMAC-SHA256 via the X-SchemaShift-Signature header when a secret is configured. Compatible with Slack, Microsoft Teams, Zapier, or any HTTP endpoint.

You can configure a custom timeout per webhook (default: 10 seconds):

{
  "url": "https://slow-api.example.com/webhook",
  "events": ["migration_completed"],
  "timeoutMs": 15000
}

Cross-Field Validation Helpers

Reusable .superRefine() code generators for common cross-field validation patterns (Pro+):

Helper Description
requireIf(conditionField, requiredField) Make a field required when another field has a value
requireOneOf(fields) At least one of N fields must be provided
mutuallyExclusive(fields) Only one of N fields can be present at a time
dependentFields(primary, dependents) Dependent fields become required when the primary is set
conditionalValidation(condition, value, target, message) Value-based conditional validation on a target field

Use suggestCrossFieldPattern(whenCode) to analyze Yup .when() patterns and get a recommended Zod equivalent.

Enhanced .when() Migration

Smart Yup .when() analysis with generated Zod replacement code (Free):

The analyzeWhenPatterns() function detects the type of .when() condition and generates the appropriate Zod replacement:

Instead of leaving a bare // TODO: handle .when(), SchemaShift generates working Zod code tailored to the specific pattern detected in your Yup schema.

Zod v4 Behavioral Test Generator

Detect silent v4 behavioral changes and generate regression test files (Pro+):

The behavioral test generator scans your Zod v3 code for 6 patterns where v4 silently changes behavior, then generates Vitest test files documenting the expected differences:

Tests are output to .schemashift/behavioral-tests/ and can be run with your existing test framework to verify v3 vs v4 behavior before committing.

Incremental Migration

Migrate large projects file-by-file with progress tracking (Pro+):

The incremental tracker persists state to .schemashift/incremental.json, allowing you to pause and resume migrations across sessions. Track completed, failed, and remaining files with percentage progress.

Tip

Incremental migration is ideal for large codebases where you want to migrate a few files at a time, verify correctness, and continue later.

Package Updates

SchemaShift can plan and apply dependency changes to your package.json during migration:

Note

SchemaShift never automatically removes source libraries. It only suggests removal after you verify all schemas have been migrated. Run npm install after applying package changes.

Schema Verification (Contract Testing)

Pro+

The schemashift verify command provides contract testing for migrated schemas, ensuring that target schemas produce the same validation behavior as source schemas.

schemashift verify ./src -f yup -t zod --samples 100

Canary Migration

Pro+

Canary migration lets you migrate a percentage of files first, verify the results, then continue with the rest. This is especially useful for large codebases where you want to validate the migration approach before committing fully.

# Migrate 20% of files (simplest first)
schemashift migrate ./src -f yup -t zod --canary 20

# Verify, then continue with remaining files
schemashift migrate ./src -f yup -t zod

Files are selected by size (smallest/simplest first) using the IncrementalTracker. State is persisted so you can resume at any point.

Duration Estimation

Individual+

The complexity estimator now includes duration estimation, providing time range estimates based on the migration's effort level and file count:

Effort Level Base Range Description
Trivial 1–5 minutes Few simple schemas, no advanced patterns
Low 5–15 minutes Moderate schema count, basic patterns
Moderate 15–45 minutes Many schemas or some advanced patterns
High 1–3 hours Large codebase with complex patterns
Extreme 3–8 hours Very large codebase with many advanced patterns

Ranges scale with file count using a logarithmic factor. Duration is shown during migration when the tier allows complexity estimation.

Compliance Reports

Team

Generate compliance-ready reports from migration audit logs for regulated environments. Use the --compliance-report flag during migration:

schemashift migrate ./src -f yup -t zod --audit --compliance-report soc2

SOC2 Format

HIPAA Format

CI/CD Templates

Pro+

Ready-to-use CI/CD pipeline templates are provided for multiple platforms, complementing the existing GitHub Action:

GitLab CI

Template at templates/gitlab-ci.yml includes:

# Include in your .gitlab-ci.yml
include:
  - local: templates/gitlab-ci.yml

Azure DevOps

Template at templates/azure-pipelines.yml includes:

Pre-Commit Hooks

Pro+

Integrate governance checks into your git workflow. The hooks command automatically detects husky and lint-staged:

# Install hooks (auto-detects husky/lint-staged)
schemashift hooks install

# Check hook status
schemashift hooks status

# Remove hooks
schemashift hooks uninstall

Once installed, governance checks run automatically on pre-commit, catching schema violations before they reach your repository.

Policy-as-Code

Team

The policy command provides structured management of schema governance policies for your organization:

Policies build on top of the existing governance engine, providing a more structured workflow for enforcing schema standards across teams.

Tiers & Features

Feature Free Individual ($49) Pro ($149) Team ($29/mo)
Migrations
Yup → Zod
Joi → Zod
Zod v3 → v4
io-ts → Zod
Zod ↔ Valibot
Zod → Yup
Valibot → Zod
Reports & Output
JSON reports
HTML reports
CSV export
Analysis & Safety
Custom rules Up to 5 Unlimited Unlimited Unlimited
Git integration
Advanced analysis
Risk scoring
Compatibility checking
Cross-file resolution
Chain migrations
Ecosystem detection
Incremental migration
Standard Schema detection
Package.json updates
Form resolver migration
Complexity estimation
TODO resolution summary
Monorepo-aware migration
Ecosystem upgrade commands
Behavioral warnings
Bundle size estimation
Performance analysis
Type deduplication
Dead schema detection
Import deduplication
Test scaffolding
CI/CD & Automation
CI/CD support
Watch mode
--fail-on-warnings
--max-risk-score
Enterprise
Devices 1 1 4 Unlimited
Custom plugins
Schema governance
Audit logging
New Features
Doctor command
Unified diff export
Dry-run summary table
Duration estimation
Compare command
Schema verification
Canary migration
Pre-commit hooks
GitLab CI / Azure DevOps templates
Policy-as-code
Compliance reports (SOC2/HIPAA)
Slack/Teams webhook formatting

View pricing and purchase →

Activation

After purchasing, you'll receive a license key via email. Activate it:

schemashift license --activate SCHEMASHIFT_PRO_xxxx-xxxx-xxxx

Your license is stored locally at ~/.config/schemashift/license.json.

Moving to Another Device

Deactivate on your current device first:

schemashift license --deactivate

Then activate on the new device with the same key.

CI/CD Setup

Requires Pro or Team license.

Set the SCHEMASHIFT_LICENSE_KEY environment variable in your CI platform:

GitHub Actions

name: Schema Migration Check

on: [push]

jobs:
  migrate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22

      - run: npm install -g schemashift-cli

      - name: Check for Yup schemas
        run: schemashift analyze ./src --json

      - name: Dry run migration
        env:
          SCHEMASHIFT_LICENSE_KEY: ${{ secrets.SCHEMASHIFT_LICENSE_KEY }}
        run: schemashift migrate ./src --from yup --to zod --dry-run --ci

GitLab CI

A ready-to-use template is available at templates/gitlab-ci.yml. Minimal example:

schema-check:
  image: node:22
  script:
    - npm install -g schemashift-cli
    - schemashift migrate ./src --from yup --to zod --dry-run --ci
  variables:
    SCHEMASHIFT_LICENSE_KEY: $SCHEMASHIFT_LICENSE_KEY
  artifacts:
    reports:
      junit: migration-report.xml

Azure DevOps

A ready-to-use template is available at templates/azure-pipelines.yml. Minimal example:

steps:
  - script: |
      npm install -g schemashift-cli
      schemashift migrate ./src --from yup --to zod --ci \
        --report junit --report-output $(Build.ArtifactStagingDirectory)/results.xml
    env:
      SCHEMASHIFT_LICENSE_KEY: $(SCHEMASHIFT_LICENSE_KEY)
  - task: PublishTestResults@2
    inputs:
      testResultsFiles: '$(Build.ArtifactStagingDirectory)/results.xml'
Tip

The --ci flag exits with code 1 if any migration fails, making it suitable for CI pipelines. Use --output-diff - to include unified diff output in your CI logs.

Troubleshooting

License activation fails

"Migration requires higher tier"

Some migration paths (io-ts, Zod↔Valibot, ArkType, Superstruct, Effect Schema) require paid tiers. Run schemashift pricing to see what's included in each tier. Yup→Zod and Joi→Zod are available in the Free tier.

"No handler for migration"

The requested migration path isn't supported. Supported paths:

Transformation produces incorrect code

  1. Run with --dry-run first
  2. Use schemashift rollback to restore from backup
  3. Report the issue with the original code snippet

Offline usage

SchemaShift validates your license weekly. You can work offline for up to 7 days after the last successful validation.

Support

Pro & Team

Priority support with faster response times for paid license holders.