Migrate Zod to ArkType

A comprehensive guide to converting Zod schemas to ArkType's string-based type system. Learn how to replace z.object({}) with type({}), convert method chains to concise string syntax like "string.email", and leverage ArkType's superior TypeScript inference.

Quick Start

Convert your Zod schemas to ArkType with one command:

npx schemashift-cli migrate ./src --from zod --to arktype
Pro+ Feature

Zod to ArkType migration requires a Pro or Team license. View pricing.

Before & After

BEFORE — Zod
// schemas/user.ts
import { z } from 'zod';

const UserSchema = z.object({
  id: z.string().uuid(),
  name: z.string().min(1).max(100),
  email: z.string().email(),
  age: z.number().int().positive(),
  role: z.enum(['admin', 'user', 'guest']),
  isActive: z.boolean(),
  tags: z.array(z.string()),
  score: z.number().optional(),
});

type User = z.infer<typeof UserSchema>;

const ResponseSchema = z.union([
  z.object({ status: z.literal('ok'), data: UserSchema }),
  z.object({ status: z.literal('error'), message: z.string() }),
]);

const validated = UserSchema.parse(input);
const safe = UserSchema.safeParse(input);
AFTER — ArkType
// schemas/user.ts
import { type } from 'arktype';

const UserSchema = type({
  id: 'string.uuid',
  name: '1 <= string <= 100',
  email: 'string.email',
  age: 'number.integer > 0',
  role: "'admin' | 'user' | 'guest'",
  isActive: 'boolean',
  tags: 'string[]',
  'score?': 'number',
});

type User = typeof UserSchema.infer;

const ResponseSchema = type(
  { status: "'ok'", data: UserSchema },
  '|',
  { status: "'error'", message: 'string' }
);

const validated = UserSchema.assert(input);
const safe = UserSchema(input);

Conversion Reference

Zod ArkType Notes
z.string() 'string' String literal syntax
z.number() 'number'
z.boolean() 'boolean'
z.object({ ... }) type({ ... })
z.string().email() 'string.email' Built-in string subtypes
z.string().uuid() 'string.uuid'
z.string().url() 'string.url'
z.string().min(N).max(M) 'N <= string <= M' Range expression syntax
z.number().int() 'number.integer'
z.number().positive() 'number > 0' Comparison expression
z.enum(['a', 'b']) "'a' | 'b'" Union of literals as string
z.literal('x') "'x'" Quoted string literal
z.array(z.string()) 'string[]' Array shorthand
.optional() 'type?' (in object key) Append ? to the key name
z.union([A, B]) type(A, '|', B) Infix union syntax
z.infer<typeof X> typeof X.infer Property access, not generic
.refine(fn) .narrow(fn)
.transform(fn) .pipe(fn)
z.record(K, V) type('Record<string, V>') Uses TypeScript syntax
schema.parse(input) schema.assert(input) Throws on failure
schema.safeParse(input) schema(input) Returns data or ArkErrors

Edge Cases & Gotchas

Automated Migration with SchemaShift

# Dry run to see what changes
npx schemashift-cli migrate ./src --from zod --to arktype --dry-run

# Run the migration
npx schemashift-cli migrate ./src --from zod --to arktype

# With verbose output
npx schemashift-cli migrate ./src --from zod --to arktype --verbose --report html

# Check compatibility first
npx schemashift-cli compat ./src --from zod --to arktype

Manual Migration Checklist

Frequently Asked Questions

What is ArkType's string-based type system?

ArkType uses string literals to define types instead of method chains. For example, z.string().email() in Zod becomes simply 'string.email' in ArkType. Object schemas use type({ name: 'string', age: 'number' }) instead of z.object({ name: z.string(), age: z.number() }). This provides more concise syntax with full TypeScript type inference.

How do I handle Zod .refine() in ArkType?

Zod's .refine() maps to ArkType's .narrow() method. For example, z.number().refine(n => n > 0) becomes type('number').narrow(n => n > 0). For more complex validation with type narrowing, ArkType's .narrow() provides stronger TypeScript inference than Zod's refine.

Does ArkType support branded types like Zod?

ArkType does not have a direct equivalent to Zod's .brand(). If you rely on branded types for nominal typing, you will need to use TypeScript's built-in branded type pattern (intersection with a unique symbol) or restructure your type system. SchemaShift adds TODO comments for branded type usage that needs manual attention.

Related Guides

Ready to try ArkType?

SchemaShift converts Zod schemas to ArkType's string syntax automatically, handling type expressions, optional keys, and import rewriting.

Get SchemaShift