8. zod/miniによるTree-ShakingとJITコンパイル

Zod v4はモジュラーな3層アーキテクチャ(zod/v4/core -> zod Classic / zod/mini + zod/compile)の上に構築されています。モバイルWeb向けに zod/mini でバンドルサイズを 約1.9 KB (gzip) まで極小化したい場合でも、高スループットなNode.js / Bunバックエンドで zod/compile のJITコード生成によってCPU負荷を最小化したい場合でも、型安全性を一切損なうことなく最適な実行モードを選択できます。

08_mini_and_jit_compilation_1
Zod v4 アーキテクチャ: 共有コア・Classicメソッドチェーン・Tree-Shake対応zod/mini・JITコンパイラ
Source Code
from drawlib.canvas import save, setup
from drawlib.icons import phosphor
from drawlib.lines import line
from drawlib.shapes import rectangle
from drawlib.smartarts import Panel
from drawlib.styles import Colors, Styles
from drawlib.text import text

setup(width=160, height=78)

text(
    (80, 73.5),
    "Zod v4 モジュラーアーキテクチャ: Classic / zod/mini / JITコンパイラ",
    style=Styles.PrimaryBold.patch(text_size=13.5),
)

# Top Foundation Banner: zod/v4/core
rectangle((80, 61.5), width=148, height=11, style=Styles.PrimaryNeutral.patch(shape_r=2.0))
phosphor.cpu((18, 61.5), width=5.5, style=Styles.Primary)
text(
    (84, 63.5),
    "共通コア基盤パッケージ: zod/v4/core (core.$ZodType, Checks, Errors, Registries, JSON Schema)",
    style=Styles.PrimaryBold.patch(text_size=10.5),
)
text(
    (84, 59.2),
    "ライブラリ作者は core.$ZodType を受け取ることで Classic と Mini の両方を透過的にサポート可能",
    style=Styles.Neutral.patch(text_size=10.0),
)

# Column 1: Classic `zod`
Panel(
    "1. Classic (zod)",
    style=Styles.Neutral.patch(shape_fill_color=Colors.White),
    header_style=Styles.PrimaryNeutral,
    text_style=Styles.PrimaryBold.patch(text_size=11.0),
    header_align="center",
).draw((6, 6), width=46, height=46)

rectangle((29, 36.5), width=40, height=11, style=Styles.Neutral.patch(shape_r=1.5))
text((29, 38.8), "直感的なメソッドチェーン", style=Styles.PrimaryBold.patch(text_size=10.5))
text((29, 34.5), "z.string().min(5).trim()", style=Styles.Neutral.patch(text_size=10.0))

rectangle((29, 22.5), width=40, height=11, style=Styles.Neutral.patch(shape_r=1.5))
text((29, 24.8), "豊富なプロトタイプメソッド", style=Styles.PrimaryBold.patch(text_size=10.5))
text((29, 20.5), ".optional() .nullable() .meta()", style=Styles.Neutral.patch(text_size=10.0))

text((29, 11.5), "最適: フルスタック開発 & DX重視", style=Styles.PrimaryBold.patch(text_size=10.0))

# Column 2: Functional `zod/mini`
Panel(
    "2. 関数型 (zod/mini)",
    style=Styles.Neutral.patch(shape_fill_color=Colors.White),
    header_style=Styles.PrimaryFlat,
    text_style=Styles.WhiteBold.patch(text_size=11.0),
    header_align="center",
).draw((57, 6), width=46, height=46)

rectangle((80, 36.5), width=40, height=11, style=Styles.PrimaryNeutral.patch(shape_r=1.5))
text((80, 38.8), "Tree-Shake可能なCheck関数", style=Styles.PrimaryBold.patch(text_size=10.5))
text((80, 34.5), "z.string().check(z.minLength(5))", style=Styles.Neutral.patch(text_size=10.0))

rectangle((80, 22.5), width=40, height=11, style=Styles.PrimaryNeutral.patch(shape_r=1.5))
text((80, 24.8), "独立したラッパー関数群", style=Styles.PrimaryBold.patch(text_size=10.5))
text((80, 20.5), "z.optional( z.nullable(...) )", style=Styles.Neutral.patch(text_size=10.0))

text((80, 11.5), "最適: ~1.9 KB フロントエンド", style=Styles.PrimaryBold.patch(text_size=10.0))

# Column 3: JIT `zod/compile`
Panel(
    "3. JITコンパイラ (zod/compile)",
    style=Styles.Neutral.patch(shape_fill_color=Colors.White),
    header_style=Styles.AccentFlat,
    text_style=Styles.WhiteBold.patch(text_size=10.5),
    header_align="center",
).draw((108, 6), width=46, height=46)

rectangle((131, 36.5), width=40, height=11, style=Styles.SecondaryNeutral.patch(shape_r=1.5))
text((131, 38.8), "高速パスJSコード生成", style=Styles.SecondaryBold.patch(text_size=10.5))
text((131, 34.5), "z.compile(schema) / new Function", style=Styles.Neutral.patch(text_size=10.0))

rectangle((131, 22.5), width=40, height=11, style=Styles.Neutral.patch(shape_r=1.5))
text((131, 24.8), "完全互換の自動フォールバック", style=Styles.PrimaryBold.patch(text_size=10.5))
text((131, 20.5), "エラー時やCSP環境は通常実行へ", style=Styles.Neutral.patch(text_size=10.0))

text((131, 11.5), "最適: 高スループットAPI基盤", style=Styles.SecondaryBold.patch(text_size=10.0))

# Arrows from Core to 3 columns
line((29, 56), (29, 52), arrow_head="->", style=Styles.PrimaryBold)
line((80, 56), (80, 52), arrow_head="->", style=Styles.PrimaryBold)
line((131, 56), (131, 52), arrow_head="->", style=Styles.PrimaryBold)

save()

1. なぜ zod/mini が必要なのか(Tree-Shakingの仕組み)

Classic版の zod では、.min()・.max()・.trim()・.optional()・.nullable()・.default() などの便利なメソッドが ZodType.prototype や ZodString.prototype に定義されています。しかし、JavaScriptのバンドラー(Vite、Rollup、esbuild、Webpack)はクラスのプロトタイプメソッドのうちどれが未使用かを静的に証明できないため、Zod v3では z.boolean() を1つインポートするだけでも多数のメソッド定義がバンドルに含まれていました。

zod/mini は、スキーマインスタンスのメソッドを最小限のコア操作(parse、safeParse、parseAsync、safeParseAsync、check、clone、register、brand、apply)のみに絞り込み、すべてのバリデーションチェック・文字列変換・ラッパーを 独立したトップレベル関数 として提供することで、完全なTree-Shakingを実現しています。

構文比較: Classic zod vs. 関数型 zod/mini

操作内容 Classic zod (import * as z from "zod") 関数型 zod/mini (import * as z from "zod/mini")
文字列の長さ制約 z.string().min(3).max(20) z.string().check(z.minLength(3), z.maxLength(20))
文字列の正規化 z.string().trim().toLowerCase() z.string().check(z.trim(), z.toLowerCase())
数値の範囲・倍数 z.number().gte(0).lt(100).multipleOf(5) z.number().check(z.gte(0), z.lt(100), z.multipleOf(5))
Set / Map の要素数 z.set(z.string()).min(1).max(10) z.set(z.string()).check(z.minSize(1), z.maxSize(10))
カスタム検証 schema.refine((val) => isValid(val)) schema.check(z.refine((val) => isValid(val)))
値のインプレース変換 schema.overwrite((val) => val.trim()) schema.check(z.overwrite((val) => val.trim()))
Optional / Nullable z.string().optional().nullable() z.nullable(z.optional(z.string()))
デフォルト値設定 z.string().default("guest") z._default(z.string(), "guest") / z.prefault(...)
オブジェクト操作 User.pick({ id: true }).partial() z.partial(z.pick(User, { id: true }))
import * as z from "zod/mini";

// 実際にインポートして使用したスキーマとチェック関数だけがクライアントバンドルに含まれます!
const SignupFormSchema = z.object({
  username: z.string().check(
    z.trim(),
    z.minLength(3, { error: "3文字以上で入力してください" }),
    z.maxLength(24),
    z.regex(/^[a-zA-Z0-9_]+$/)
  ),
  email: z.email(),
  age: z.optional(z.number().check(z.int(), z.gte(18))),
  marketingOptIn: z._default(z.boolean(), false),
});

type SignupForm = z.infer<typeof SignupFormSchema>;
// { username: string; email: string; age?: number | undefined; marketingOptIn: boolean }

const result = SignupFormSchema.safeParse({
  username: "  alice_dev  ",
  email: "alice@example.com",
});
// result.data -> { username: "alice_dev", email: "alice@example.com", marketingOptIn: false }

2. バンドルサイズと実行スループットの比較

08_mini_and_jit_compilation_2
Zod v3およびv4各モードにおけるGzipバンドルサイズ(KB)と相対パース速度の比較

3. zod/v4/core を使った共通ライブラリの設計

オープンソースのUIライブラリや社内共通SDKを開発する場合、利用者に zod と zod/mini のどちらか一方を強制すべきではありません。両方のパッケージはすべて zod/v4/core の同一トレイト($ZodType)を継承しています。

ライブラリの関数引数を core.$ZodType で型付けし、core.parse・core.safeParse・core.toJSONSchema などのトップレベル関数を呼び出すことで、zod と zod/mini のどちらで定義されたスキーマもそのまま受け取ることができます:

import * as core from "zod/v4/core";

// Classic版の `ZodType` と Mini版の `ZodMiniType` の両方を透過的に受け取る汎用関数
export function validateEnv<T extends core.$ZodType>(
  schema: T,
  env: Record<string, string | undefined>
): core.output<T> {
  const result = core.safeParse(schema, env);
  if (!result.success) {
    throw new Error(
      `環境変数の検証に失敗しました:\n${core.prettifyError(result.error)}`
    );
  }
  return result.data;
}

4. z.compile() と zod/compile によるJITコンパイル高速化

APIゲートウェイ、メッセージキューワーカー、大量のJSONL/CSVバッチ処理など、CPUバウンドなバックエンドサービス向けに、Zod v4は JIT (Just-In-Time) / AOT スキーマコンパイラ を搭載しています。

JITコンパイラの内部動作とハイブリッド・フォールバック

スキーマをコンパイルすると、Zodは _zod.def のASTを走査し、型チェック・プロパティ参照・正規表現テスト・数値範囲判定をフラットなローカル変数へインライン展開した専用のJavaScript関数(new Function)を生成します:

  1. 正常系(Happy Path)の超高速実行: 同期的な順方向パース(schema.parse(data) および schema.safeParse(data))では、生成されたJS関数が直接実行され、クロージャ割り当てやディスパッチのオーバーヘッドなしに新しい出力オブジェクトを構築します。
  2. 異常系(Error Path)での完全互換フォールバック: 入力データに不正な値が含まれていた場合、コンパイル済み関数は即座に内部センチネル Symbol.for("zod.compile.invalid") (z.INVALID) を返し、通常のランタイムインタプリタへ処理を引き継ぎます。これにより、4段階のエラー優先順位チェーン・ネストされたIssueパス・多言語ロケールメッセージが100%完全に維持されます。
  3. 非同期・逆方向(Encode)の自動バイパス: .parseAsync() や .encode()、skipChecks オプション付き呼び出しは自動的にランタイムインタプリタで処理されます。

利用パターンA: ホットパスの個別コンパイル (z.compile())

特定の高頻度スキーマだけを明示的にコンパイルしたい場合は、z.compile(schema) を使用します(元のスキーマは変更されず、高速パスを持つクローンが返されます):

import * as z from "zod";

const TelemetryEventSchema = z.object({
  eventId: z.uuid(),
  timestamp: z.number().int().positive(),
  service: z.enum(["auth", "billing", "search"]),
  latencyMs: z.number().gte(0).lte(60_000),
  tags: z.array(z.string().min(1).max(32)),
});

// 最適化された `_zod.run` 高速パスを持つコンパイル済みクローンを生成
const FastTelemetrySchema = z.compile(TelemetryEventSchema);

// APIやエラーメッセージは完全に同一のまま、さらに約3倍高速に検証!
const event = FastTelemetrySchema.parse({
  eventId: "550e8400-e29b-41d4-a716-446655440000",
  timestamp: 1735689600000,
  service: "billing",
  latencyMs: 14.2,
  tags: ["prod", "us-east1"],
});

デフォルトでは、非同期リファインメントなどJITコンパイル非対応の機能がスキーマに含まれている場合でも、z.compile(schema) は例外を投げずに元のスキーマをそのまま返すため安全です。テストコード等で非対応スキーマを厳密に検出したい場合は、z.compile(schema, { strict: true }) を渡すことで ZodCompileUnsupportedError / ZodCompileAsyncError をスローさせることができます。

利用パターンB: アプリケーション全体の自動JIT化 (import "zod/compile")

バックエンドサーバー内の すべてのスキーマ を初回パース時に自動でJITコンパイルしたい場合は、アプリケーションのエントリーポイント最上部で "zod/compile" を副作用インポートします:

// スキーマを定義するどのモジュールよりも先(エントリーポイント最上部)でインポートします
import "zod/compile";
import * as z from "zod";

// これ以降に生成されるすべてのスキーマに遅延JITコンパイル用shimが自動装着されます
const RequestSchema = z.object({
  userId: z.string().min(1),
  action: z.enum(["read", "write"]),
});

// 初回の同期 .parse() / .safeParse() 実行時にJITコンパイルされ、_zod.run が置き換わります
RequestSchema.parse({ userId: "u_123", action: "read" });

5. Content Security Policy (CSP) 環境と jitless モード

ブラウザ拡張機能、厳格なContent-Security-Policy('unsafe-eval' を許可しない script-src)が適用されたWebアプリ、あるいは一部のエッジランタイムでは、new Function() による動的コード生成が禁止されている場合があります。

Zod v4では z.config({ jitless: true }) を設定することで、コアのEnumチェックおよび zod/compile の両方において new Function の呼び出しを完全に無効化し、安全なランタイムインタプリタ実行へフォールバックさせることができます:

import * as z from "zod";

// 厳格なCSP環境で `new Function` によるJITコード生成を無効化
z.config({ jitless: true });

ESモジュールが読み込まれる前のHTML <script> タグ内で事前に設定したい場合は、globalThis.__zod_globalConfig = { jitless: true }; を代入しておくことでも即座に反映されます。また、ビルド時にAOT生成した検証関数を注入したいツールチェーン向けには、new Function を一切使わずに高速パスを装着できる z.withParser(schema, precompiledFn) も提供されています。


まとめと関連ポータル

以上で Zod v4.6.7 ユーザーガイド の全8章は完了です!個別APIの詳細シグネチャや内部実装アーキテクチャ、診断レポートについては以下の関連ポータルをご活用ください: