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
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"
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:
- Schema library detection — identifies Zod, Yup, Joi, Valibot, io-ts, and their versions from
package.json - Outdated version detection — flags Zod v3 when v4 is available, suggests Yup/Joi→Zod migration
- Form library compatibility — detects react-hook-form + yup and suggests resolver migration
- Ecosystem dependency checks — identifies drizzle-zod, tRPC, and other packages that may need updating
- Config validation — checks
.schemashiftrc.jsonfor issues - Actionable suggestions — provides runnable SchemaShift commands based on detected state
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:
- Extracts schema names from source files (supports Zod, Yup, Joi, Valibot patterns)
- Generates test samples (valid + invalid boundary data) based on schema structure
- Validates samples through both source and target schemas
- 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) |
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() |
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(),
});
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()) |
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.
| Zod | ArkType |
|---|---|
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.
| Zod | Superstruct |
|---|---|
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-ts | Effect Schema |
|---|---|
t.string | S.String |
t.number | S.Number |
t.boolean | S.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 |
Individual+ tiers include automatic form resolver migration:
yupResolver → zodResolver,
joiResolver → zodResolver,
zodResolver → valibotResolver
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
|
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.
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):
- branded-types — io-ts branded type patterns needing manual conversion
- io-ts-codecs — Codec/decoder patterns with Either monad handling
- fp-ts-patterns — Functional programming patterns from fp-ts
- form-migration — Form library adapter changes needed
- custom-validation — Custom validators requiring manual review
- manual-review — General patterns needing human judgment
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+):
- Detects npm, Yarn, and pnpm workspaces from
package.json - Identifies which schema library each package uses
- Produces a topologically sorted migration order based on inter-package dependencies
- Ensures leaf packages migrate before dependents to prevent breakage
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.
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.
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):
- no-any-schemas — disallow
z.any(),yup.mixed(),Joi.any() - require-descriptions — all schemas must have
.describe() - max-nesting-depth — limit schema nesting depth (configurable threshold)
- no-deprecated-methods — flag
.deepPartial(),.strip(),.promise() - naming-convention — enforce schema naming pattern (configurable regex)
- require-max-length — string schemas must include
.max()
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
migration_started— fired when a migration beginsmigration_completed— fired on successful migrationmigration_failed— fired when a migration failsgovernance_violation— fired when governance rules are violateddrift_detected— fired when schema drift is detected
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"
}
]
}
"slack"— sends Slack Block Kit format (header + section with fields + context)"teams"— sends Microsoft Teams Adaptive Card format (TextBlock + FactSet)"generic"(default) — sends raw event JSON payload
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:
- Boolean discriminator →
z.discriminatedUnion() - Enum discriminator →
z.discriminatedUnion() - Presence check →
z.union()+.superRefine() - Simple either/or →
z.union() - Complex condition →
.superRefine()template
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:
.default()+.optional()—.default()always provides a value, making.optional()a no-opinstanceof Error—ZodErrorno longer extendsError.transform()after.refine()— transforms now run even when refinements fail.catch()+.optional()—.catch()catches all issues- Error message format changes
.flatten()API changes
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.
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:
- Adds the target library if not already installed (e.g., adds
zodfor yup→zod) - Updates version ranges when needed (e.g.,
zod ^3.x→^4.0.0for v3→v4) - Suggests removal of source libraries after migration (never auto-removes)
- Handles both
dependenciesanddevDependencies
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.
- Schema extraction — identifies schema definitions from source code (Zod, Yup, Joi, Valibot patterns and exports)
- Sample generation — creates valid and invalid test data based on detected schema patterns (string, number, boolean, email, url, uuid, optional, nullable)
- Parity scoring — compares pass/fail results between source and target, reporting an overall parity score
- Mismatch reporting — details which samples produced different results and why
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
- Change Control Summary — total entries, success rate, date range
- Entry Details — change control IDs, timestamps, risk scores, warnings
- Rollback Procedure — backup verification and restore commands
HIPAA Format
- Data Transformation Summary — total entries, success rate, date range
- Integrity Verification — SHA-256 content hashes for each transformation
- Access Control — hostname, user, CI provider, job ID for each operation
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:
schemashift-migratejob with JUnit report artifactsschemashift-analyzejob with JSON outputschemashift-governancejob for Team tier
# Include in your .gitlab-ci.yml
include:
- local: templates/gitlab-ci.yml
Azure DevOps
Template at templates/azure-pipelines.yml includes:
- Analyze job with build artifact publishing
- Migrate job with JUnit test results integration
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:
schemashift policy init— generates a policy file from built-in governance templatesschemashift policy check <path>— runs governance checks with active policiesschemashift policy list— shows available governance templates grouped by category
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 | — | — | — | ✓ |
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'
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
- Check your internet connection
- Verify the key is correct (no extra spaces)
- If you've hit the device limit, deactivate another device first
"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:
yup→zodjoi→zodzod-v3→v4io-ts→zodzod↔valibotzod→yupvalibot→zodzod↔arktypezod↔superstructio-ts→effect(Effect Schema)
Transformation produces incorrect code
- Run with
--dry-runfirst - Use
schemashift rollbackto restore from backup - 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
- Email: support@qwady.com
- Issues: Email with code samples for transformation bugs
Priority support with faster response times for paid license holders.