1. 3-Tier Package Topology (v4/core, classic, mini)

Zod v4.6.7 organizes its packages/zod/src/ directory into a strict Directed Acyclic Graph (DAG) across three primary architectural tiers (v4/core, v4/classic, v4/mini), supplemented by 64 localization modules (v4/locales) and thin package subpath entrypoints. Every dependency arrow points strictly downward: v4/core has zero imports from v4/classic or v4/mini, and v4/classic and v4/mini never import each other.

01_package_and_layers_1
Directed Acyclic Dependency Graph (DAG) of packages/zod/src/ Showing Downward-Only Imports
Source Code
from drawlib.canvas import save, setup
from drawlib.icons import phosphor
from drawlib.lines import line
from drawlib.smartarts import CardList, Panel
from drawlib.styles import Styles
from drawlib.text import text

setup(width=156, height=110)

text(
    (78, 105.5),
    "Zod v4.6.7 Module Dependency DAG (packages/zod/src/)",
    style=Styles.DarkBold.patch(text_size=13.5),
)
text(
    (78, 101.5),
    "Strict Downward-Only Imports from Subpath Entrypoints -> Classic/Mini Facades -> Core & Locales",
    style=Styles.Muted.patch(text_size=10.0),
)

# Tier 0: Top-level Entrypoints
p_top = Panel(
    "Subpath Entrypoints (packages/zod/src/*.ts)",
    style=Styles.Neutral,
    header_style=Styles.Secondary,
    text_style=Styles.WhiteBold.patch(text_size=10.5),
    header_height=5.8,
)
p_top.draw(xy=(6, 80), width=144, height=17.5)

top_cards = CardList(
    style=Styles.White,
    text_style=Styles.DarkBold.patch(text_size=9.5),
    description_style=Styles.Muted.patch(text_size=9.5),
    badge_shape="none",
    direction="horizontal",
    spacing=2.0,
)
top_cards.add("src/index.ts", description="export { z, z as default }", style=Styles.PrimaryNeutral)
top_cards.add("src/locales/index.ts", description="49+ locale barrel")
top_cards.add("src/v4/core/index.ts", description="core barrel export")
top_cards.add("src/compile.ts", description="AOT postProcessor")
top_cards.add("src/mini/index.ts", description="re-exports v4/mini", style=Styles.PrimaryNeutral)
top_cards.draw(xy=(8.5, 81.5), width=139, height=8.5)

# Tier 1 Left: v4/classic (12 modules)
p_classic = Panel(
    "v4/classic/ (12 Modules)",
    style=Styles.PrimaryNeutral,
    header_style=Styles.Primary,
    text_style=Styles.WhiteBold.patch(text_size=10.5),
    icon=phosphor.stack,
    icon_style=Styles.White,
    header_height=5.8,
)
p_classic.draw(xy=(6, 45), width=52, height=28)

classic_list = CardList(
    style=Styles.White,
    text_style=Styles.DarkBold.patch(text_size=9.5),
    description_style=Styles.Muted.patch(text_size=9.5),
    badge_shape="none",
    direction="vertical",
    spacing=1.5,
)
classic_list.add("external.ts & schemas.ts", description="ZodType + 35+ chain methods")
classic_list.add("from-json-schema.ts", description="JSON Schema parser + compat.ts")
classic_list.draw(xy=(8.5, 47.0), width=47, height=18.0)

# Tier 1 Center: v4/locales (64 files) — adjacent to v4/classic
p_loc = Panel(
    "v4/locales/ (64 Files)",
    style=Styles.Neutral,
    header_style=Styles.Secondary,
    text_style=Styles.WhiteBold.patch(text_size=10.5),
    icon=phosphor.globe,
    icon_style=Styles.White,
    header_height=5.8,
)
p_loc.draw(xy=(66, 45), width=34, height=28)

loc_list = CardList(
    style=Styles.White,
    text_style=Styles.DarkBold.patch(text_size=9.5),
    description_style=Styles.Muted.patch(text_size=9.5),
    badge_shape="none",
    direction="vertical",
    spacing=1.5,
)
loc_list.add("en.ts (Default)", description="Auto-loaded by classic")
loc_list.add("ja.ts, de.ts, fr.ts...", description="Opt-in via z.config()")
loc_list.draw(xy=(68.0, 47.0), width=30, height=18.0)

# Tier 1 Right: v4/mini (9 modules)
p_mini = Panel(
    "v4/mini/ (9 Modules)",
    style=Styles.PrimaryNeutral,
    header_style=Styles.Primary,
    text_style=Styles.WhiteBold.patch(text_size=10.5),
    icon=phosphor.feather,
    icon_style=Styles.White,
    header_height=5.8,
)
p_mini.draw(xy=(104, 45), width=46, height=28)

mini_list = CardList(
    style=Styles.White,
    text_style=Styles.DarkBold.patch(text_size=9.5),
    description_style=Styles.Muted.patch(text_size=9.5),
    badge_shape="none",
    direction="vertical",
    spacing=1.5,
)
mini_list.add("external.ts & schemas.ts", description="ZodMiniType (no method chains)")
mini_list.add("checks.ts, parse.ts, iso.ts", description="Tree-shakable check functions")
mini_list.draw(xy=(106.5, 47.0), width=41, height=18.0)

# Tier 2 Bottom: v4/core (21 modules)
p_core = Panel(
    "v4/core/ — Shared Validation, Trait & Compiler Engine (21 Modules — Zero Upward Dependencies)",
    style=Styles.Neutral,
    header_style=Styles.PrimaryFlat,
    text_style=Styles.WhiteBold.patch(text_size=10.5),
    icon=phosphor.cpu,
    icon_style=Styles.White,
    header_height=5.8,
)
p_core.draw(xy=(6, 5), width=144, height=33)

core_r1 = CardList(
    style=Styles.White,
    text_style=Styles.DarkBold.patch(text_size=9.5),
    description_style=Styles.Muted.patch(text_size=9.5),
    badge_shape="none",
    direction="horizontal",
    spacing=2.5,
)
core_r1.add(
    "core.ts & util.ts",
    description="$constructor, globalConfig, clone()",
    style=Styles.PrimaryFlat,
    text_style=Styles.WhiteBold.patch(text_size=9.5),
    description_style=Styles.White.patch(text_size=9.5),
)
core_r1.add(
    "schemas.ts & api.ts",
    description="$ZodType & shared _string factories",
    style=Styles.PrimaryNeutral,
)
core_r1.add(
    "checks.ts, regexes.ts & parse.ts",
    description="$ZodCheck, RegExps, _parse, _encode",
)
core_r1.draw(xy=(8.5, 20.5), width=139, height=9.5)

core_r2 = CardList(
    style=Styles.White,
    text_style=Styles.DarkBold.patch(text_size=9.5),
    description_style=Styles.Muted.patch(text_size=9.5),
    badge_shape="none",
    direction="horizontal",
    spacing=2.5,
)
core_r2.add(
    "doc.ts & compile.ts",
    description="Doc closure builder & JIT compiler",
    style=Styles.AccentFlat,
    text_style=Styles.WhiteBold.patch(text_size=9.5),
    description_style=Styles.White.patch(text_size=9.5),
)
core_r2.add(
    "registries.ts & memoizer.ts",
    description="WeakMap registry & cycle memoizer",
)
core_r2.add(
    "to-json-schema.ts & standard-schema",
    description="JSON Schema Drafts & ~standard v1",
)
core_r2.draw(xy=(8.5, 8.0), width=139, height=9.5)

# Downward arrows (gap = 7.0 units)
line((32, 80), (32, 73), arrow_head="->", style=Styles.PrimaryBold)
line((83, 80), (83, 73), arrow_head="->", style=Styles.SecondaryBold)
line((127, 80), (127, 73), arrow_head="->", style=Styles.PrimaryBold)

# Classic imports en.ts from adjacent locales (gap = 8.0 units)
line((58, 59), (66, 59), arrow_head="->", style=Styles.SecondaryBold)
text((62, 62.0), "en()", style=Styles.Secondary.patch(text_size=9.5))

# Classic, Locales, Mini -> Core (gap = 7.0 units)
line((32, 45), (32, 38), arrow_head="->", style=Styles.PrimaryBold)
text((44, 41.5), "import * as core", style=Styles.Primary.patch(text_size=9.5))

line((83, 45), (83, 38), arrow_head="->", style=Styles.SecondaryBold)

line((127, 45), (127, 38), arrow_head="->", style=Styles.PrimaryBold)
text((139, 41.5), "import * as core", style=Styles.Primary.patch(text_size=9.5))

save()

1. Complete Module Inventory Across All Four Directories

1.1 packages/zod/src/v4/core/ (21 Modules — The Engine)

v4/core contains every runtime algorithm, type-level inference primitive, check implementation, JIT compiler pass, and JSON Schema processor. None of its 21 modules attach convenience wrapper methods (such as .optional() or .min()) onto schema prototypes.

Module (v4/core/) Size / Scale Core Responsibility & Exported Symbols
core.ts ~9.7 KB Defines $constructor(), NEVER, newError(), $brand, input<T>, output<T>, infer<T>, and globalConfig (globalThis.__zod_globalConfig).
util.ts ~48.1 KB Foundational runtime and type utilities: Cached / cached(), defineLazy(), defineLazyInternal(), installLazyProp(), members(), derived(), clone(), mergeDefs(), aborted(), finalizeIssue(), toZod<T>(), and allowsEval.
schemas.ts ~177.1 KB (5,227 LOC) Defines $ZodType and 45+ core schema constructors ($ZodString, $ZodNumber, $ZodObject, $ZodObjectJIT, $ZodUnion, $ZodDiscriminatedUnion, $ZodPipe, $ZodCodec, etc.) plus ParsePayload and ParseContextInternal.
api.ts ~58.2 KB Shared factory helper functions (_string, _number, _email, _uuid, _isoDateTime, etc.) parameterized by a Class: util.SchemaClass<...> constructor so v4/classic and v4/mini share 100% of parameter normalization logic.
checks.ts ~39.0 KB Defines $ZodCheck and 25+ refinement/mutation check traits ($ZodCheckLessThan, $ZodCheckGreaterThan, $ZodCheckMinLength, $ZodCheckRegex, $ZodCheckStringFormat, $ZodCheckOverwrite, etc.).
parse.ts ~12.6 KB Higher-order execution runners: _parse, _parseAsync, _safeParse, _safeParseAsync, validate, validateAsync, _encode, _decode, _safeEncode, and _safeDecode.
errors.ts ~18.9 KB Discriminated issue unions ($ZodIssue, $ZodRawIssue), lazy-message $ZodError / $ZodRealError, and error formatting helpers (treeifyError, prettifyError, formatError, flattenError).
regexes.ts ~12.7 KB Precompiled regular expressions (email, uuid, ipv4, ipv6, base64, cuid2, ulid, datetime, duration, etc.) and builders.
doc.ts ~1.5 KB Doc closure code-generation buffer that formats indented JS source lines and compiles them via new Function(...Object.keys(closed), body).
compile.ts ~97.9 KB Full schema compiler (compile(), withParser()) generating specialized synchronous validators and fast-path parsers with fallback semantics.
registries.ts ~3.4 KB $ZodRegistry (WeakMap schema metadata + Map ID index), $output / $input placeholder symbols, $replace<Meta, S>, and globalRegistry.
memoizer.ts ~12.1 KB $ZodMemoizer implementation (memoizer()) enabling cyclic object/array/map/set input graphs to be parsed without infinite recursion.
to-json-schema.ts ~35.0 KB Functional JSON Schema pipeline (initializeContext, processSchema, extractDefs, finalize) supporting Draft-04, Draft-07, Draft-2020-12, and OpenAPI 3.0.
json-schema-processors.ts ~38.4 KB Per-type JSON Schema processor callbacks (stringProcessor, numberProcessor, objectProcessor, aggregateChecks, toJSONSchema).
json-schema-generator.ts ~4.6 KB Backward-compatible JSONSchemaGenerator class wrapper around to-json-schema.ts.
json-schema.ts ~3.9 KB TypeScript type definitions for JSON Schema Draft payloads (BaseSchema, ObjectSchema, etc.).
standard-schema.ts ~6.3 KB Standard Schema v1 (~standard) and Standard JSON Schema type contracts (StandardSchemaV1, StandardSchemaWithJSONProps).
visit.ts & zsf.ts ~13.6 KB Schema graph traversal (visit()) and internal schema serialization format (zsf.ts).
versions.ts & index.ts ~0.8 KB Version constant (4.6.7) and barrel export for zod/v4/core.

1.2 packages/zod/src/v4/classic/ vs. packages/zod/src/v4/mini/

Both v4/classic and v4/mini are thin facades that wrap v4/core constructors using $constructor trait composition and delegate construction to core._string(Class, params) in v4/core/api.ts:

// In packages/zod/src/v4/classic/schemas.ts:
export function string(params?: string | core.$ZodStringParams): ZodString {
  return core._string(ZodString, params);
}

// In packages/zod/src/v4/mini/schemas.ts:
export function string(params?: string | core.$ZodStringParams): ZodMiniString<string> {
  return core._string(ZodMiniString, params) as any;
}

Why does zod/mini produce ~85% smaller bundles for small client applications? There are three concrete reasons in the source code:

  1. Zero Wrapper/Refinement Methods on ZodMiniType.prototype: In v4/classic/schemas.ts (L184-357), ZodType installs over 35 methods onto its prototype (.optional(), .nullable(), .nullish(), .array(), .or(), .and(), .transform(), .default(), .catch(), .pipe(), .readonly(), .describe(), .meta(), .toJSONSchema()). Because ZodType.prototype references optional(), nullable(), array(), union(), intersection(), pipe(), transform(), and createToJSONSchemaMethod(), Rollup/esbuild/Webpack cannot tree-shake those schema constructors or the JSON Schema generator out of a zod bundle even if the application only calls z.string().parse("hi"). By contrast, ZodMiniType (v4/mini/schemas.ts:L55-103) installs only parse, parseAsync, safeParse, safeParseAsync, check (with), clone, brand, register, and apply.
  2. Zero Format Methods on ZodMiniString.prototype: In v4/classic/schemas.ts (L535-614), ZodString attaches .email(), .url(), .jwt(), .uuid(), .cuid2(), .ulid(), .ipv4(), .cidrv6(), .e164(), .datetime(), etc. Every one of those methods references ZodEmail, ZodUUID, ZodJWT, and their regular expressions in v4/core/regexes.ts. In v4/mini/schemas.ts (L116-122), ZodMiniString has no prototype methods at all; users compose checks functionally via z.string().check(z.minLength(5), z.email()), allowing bundlers to drop every unused check and regex.
  3. No Automatic Default Locale Import in v4/mini: Look at v4/classic/schemas.ts:L14-16:
    function _ensureDefaultLocale(): void {
      if (!core.globalConfig.localeError) core.config(en());
    }
    
    ZodType calls _ensureDefaultLocale() on first schema construction, which bundles v4/locales/en.ts (~5.1 KB of English error message templates) automatically. ZodMiniType omits _ensureDefaultLocale(), falling back to "Invalid input" in finalizeIssue() (v4/core/util.ts:L978) unless the developer explicitly opts into z.config(z.locales.en()) or z.config(z.locales.ja()).

2. Dual ESM/CJS Build Pipeline (zshy & @zod/source)

Zod v4 uses zshy (packages/zod/package.json:L38-126) to compile TypeScript sources under src/ into dual ESM (.js + .d.ts) and CommonJS (.cjs + .d.cts) entrypoints while supporting zero-build monorepo development via the custom @zod/source export condition.

01_package_and_layers_2
packages/zod/package.json Export Conditions, zshy Dual ESM/CJS Build Pipeline, and Tree-Shaking Guards
Source Code
from drawlib.canvas import save, setup
from drawlib.lines import line
from drawlib.smartarts import CardList, ChevronProcess, Panel
from drawlib.styles import Styles
from drawlib.text import text

setup(width=156, height=90)

text(
    (78, 85.5),
    "Package Export Resolution & zshy Dual ESM/CJS Build Pipeline",
    style=Styles.DarkBold.patch(text_size=13.5),
)

# Top pipeline chevrons
pipe = ChevronProcess(
    style=Styles.PrimaryNeutral,
    text_style=Styles.DarkBold.patch(text_size=10.0),
    description_style=Styles.Dark.patch(text_size=9.5),
    corner_angle=60.0,
    spacing=1.5,
    flat_left_end=True,
)
pipe.add(
    "1. TypeScript Source",
    description="packages/zod/src/**/*.ts",
    style=Styles.PrimaryFlat,
    text_style=Styles.WhiteBold.patch(text_size=10.0),
    description_style=Styles.White.patch(text_size=9.5),
)
pipe.add("2. zshy Build Compiler", description="tsconfig.build.json")
pipe.add("3. Postbuild & Stubs", description="write-stub-package-jsons.ts")
pipe.add(
    "4. Conditional Exports",
    description="ESM / CJS / @zod/source",
    style=Styles.AccentFlat,
    text_style=Styles.WhiteBold.patch(text_size=10.0),
    description_style=Styles.White.patch(text_size=9.5),
)
pipe.draw(xy=(6, 67), width=144, height=13)

# Left Panel: 11 Subpath Exports in package.json
p_exp = Panel(
    "11 Subpaths in package.json",
    style=Styles.Neutral,
    header_style=Styles.Primary,
    text_style=Styles.WhiteBold.patch(text_size=10.5),
    header_height=6.0,
)
p_exp.draw(xy=(6, 6), width=46, height=54)

exp_cards = CardList(
    style=Styles.White,
    text_style=Styles.DarkBold.patch(text_size=9.5),
    description_style=Styles.Muted.patch(text_size=9.5),
    badge_shape="none",
    direction="vertical",
    spacing=1.3,
)
exp_cards.add(". & ./v4", description="./src/index.ts (Classic API)", style=Styles.PrimaryNeutral)
exp_cards.add("./mini & ./v4/mini", description="./src/mini/index.ts (Mini API)", style=Styles.PrimaryNeutral)
exp_cards.add("./v4/core", description="./src/v4/core/index.ts (Engine)")
exp_cards.add("./compile", description="./src/compile.ts (Side-effect AOT)")
exp_cards.add("./locales & ./v4/locales/*", description="./src/v4/locales/* (49+ Locales)")
exp_cards.draw(xy=(8.5, 8.0), width=41, height=44.0)

# Center Panel: 4 Export Conditions per Subpath
p_cond = Panel(
    "Per-Subpath Conditions",
    style=Styles.Neutral,
    header_style=Styles.Secondary,
    text_style=Styles.WhiteBold.patch(text_size=10.5),
    header_height=6.0,
)
p_cond.draw(xy=(55, 6), width=46, height=54)

cond_cards = CardList(
    style=Styles.White,
    text_style=Styles.DarkBold.patch(text_size=9.5),
    description_style=Styles.Muted.patch(text_size=9.5),
    badge_shape="none",
    direction="vertical",
    spacing=1.5,
)
cond_cards.add(
    '"@zod/source": "./src/*.ts"',
    description="Direct TS in Vitest / monorepo",
    style=Styles.PrimaryNeutral,
)
cond_cards.add('"types": "./*.d.cts"', description="TypeScript declaration files")
cond_cards.add('"import": "./*.js"', description="Native ES Module (.js + .d.ts)")
cond_cards.add('"require": "./*.cjs"', description="Sealed CommonJS (sealCjsExports)")
cond_cards.draw(xy=(57.5, 8.0), width=41, height=44.0)

# Right Panel: Bundler Tree-Shaking Optimizations
p_shake = Panel(
    "Tree-Shaking & Purity Guarantees",
    style=Styles.Neutral,
    header_style=Styles.PrimaryFlat,
    text_style=Styles.WhiteBold.patch(text_size=10.5),
    header_height=6.0,
)
p_shake.draw(xy=(104, 6), width=46, height=54)

shake_cards = CardList(
    style=Styles.White,
    text_style=Styles.DarkBold.patch(text_size=9.5),
    description_style=Styles.Muted.patch(text_size=9.5),
    badge_shape="none",
    direction="vertical",
    spacing=1.5,
)
shake_cards.add(
    'sideEffects: ["./compile.*"]',
    description="All other modules side-effect free",
    style=Styles.AccentFlat,
    text_style=Styles.WhiteBold.patch(text_size=9.5),
    description_style=Styles.White.patch(text_size=9.5),
)
shake_cards.add("/*@__PURE__*/ Annotations", description="Marks factory calls side-effect free")
shake_cards.add("export { z, z as default }", description="Fixes Rollup/Webpack import (#6050)")
shake_cards.add("IIFE NUMBER_FORMAT_RANGES", description="Avoids Number.* dead-code retention")
shake_cards.draw(xy=(106.5, 8.0), width=41, height=44.0)

line((29, 67), (29, 60), arrow_head="->", style=Styles.PrimaryBold)
line((78, 67), (78, 60), arrow_head="->", style=Styles.SecondaryBold)
line((127, 67), (127, 60), arrow_head="->", style=Styles.PrimaryBold)

save()

2.1 Why import * as core and export { z, z as default } Matter

A subtle bundler pitfall in JavaScript module graphs is how Rollup, Webpack, and esbuild handle namespace re-exports (import * as z vs export default z). Look at the comment in packages/zod/src/index.ts:

// packages/zod/src/index.ts
import * as z from "./v4/classic/external.js";
export * from "./v4/classic/external.js";
// Aliasing the binding, instead of `export default z`, keeps the default export a
// re-export of `z` rather than a fresh namespace value. Rollup and Webpack can then
// shake `import z from "zod"` as they already shake `import { z } from "zod"` — without
// this they pull in every locale. See #6050.
export { z, z as default };

When a file writes export default z, Rollup and Webpack materialize the module namespace object as a first-class runtime value, forcing every property of external.js—including export * as locales from "../locales/index.js" (all 49+ locales!)—into the bundle. By writing export { z, z as default }, default remains a live ES module binding alias, allowing bundlers to statically resolve z.string() even when imported via import z from "zod".

2.2 Explicit sideEffects Whitelisting for zod/compile

In packages/zod/package.json:L13-17, only the AOT compilation entrypoint is listed in sideEffects:

  "sideEffects": [
    "./compile.js",
    "./compile.cjs",
    "./src/compile.ts"
  ],

Every other module in Zod v4 is treated as pure (sideEffects: false) by bundlers:

  • Every $constructor(...) call is prefixed with /*@__PURE__*/, and $constructor itself is annotated with /*@__NO_SIDE_EFFECTS__*/ (packages/zod/src/v4/core/core.ts:L51).
  • Top-level constants that read properties off built-in globals (such as Number.MIN_SAFE_INTEGER in NUMBER_FORMAT_RANGES, packages/zod/src/v4/core/util.ts:L741) are wrapped in /*@__PURE__*/ (() => ({ ... }))() IIFEs because esbuild refuses to tree-shake bare top-level object literals containing Number.* member accesses.
  • Conversely, import "zod/compile" (packages/zod/src/compile.ts) mutates core.globalConfig.postProcessor at import time to wrap every subsequently constructed schema in a lazy JIT/AOT compilation shim, so listing it in sideEffects prevents bundlers from dropping bare import "zod/compile" statements.