This page gets you from a fresh clone to a merged first change. All commands are taken from the root package.json scripts and CONTRIBUTING.md.

Setup

Requirements (from AGENTS.md): Node.js v24+ and pnpm v10.12.1 (the exact version is pinned via "packageManager": "pnpm@10.12.1" in the root package.json).

git clone git@github.com:{your_username}/zod.git
cd zod
pnpm i

pnpm i also runs husky via the prepare script, installing the git hooks described below.

Repo tour

The workspace is declared in pnpm-workspace.yaml as simply packages/*. What each package is for:

Path Package Purpose
packages/zod zod The published library. All source lives in src/: v4/core (internals), v4/classic (the zod API), v4/mini (the zod/mini API), v4/locales (error translations), v3 (legacy API, still shipped).
packages/bench @zod/benchmarks Benchmark suites run with pnpm bench <file>; compares against zod3, valibot, arktype.
packages/docs @zod/docs The zod.dev documentation site. Content in packages/docs/content.
packages/integration @zod/integration Tests the built package under real consumer setups (test:source vs test:built).
packages/resolution @zod/resolution Verifies module resolution of the published export map across environments.
packages/treeshake @zod/treeshaking Bundle-size fixtures for rollup/esbuild; one file per scenario (zod-string.ts, zod-mini-string.ts, ...).
packages/tsc @zod/tsc-perftest TypeScript compiler performance harness.

At the repo root, play.ts is a scratchpad for experimentation and rfcs/ holds design documents.

The @zod/source trick

You never need to build to run code against the library source. The dev scripts resolve the custom export condition @zod/source, which maps every zod import directly to packages/zod/src/*.ts:

package.json
"dev": "tsx --conditions @zod/source",
"dev:watch": "tsx --conditions @zod/source --watch",
"dev:play": "pnpm dev play.ts",

So the day-one loop is: edit play.ts, run pnpm dev:play, iterate. The Vitest config uses the same condition, which is why tests also run straight from source.

Running the tests

pnpm test                      # all Vitest tests, all packages
pnpm test:watch                # watch mode
pnpm vitest run packages/zod/src/v4/classic/tests/string.test.ts   # one file
pnpm vitest run <path> -t "MAC"                                    # one test by name
pnpm vitest run --update       # update inline snapshots

Note that type-level assertions run as part of the same suite: the root vitest.config.ts enables typecheck with checker: "tsc", so expectTypeOf assertions in *.test.ts files are compiled and verified. Also, the setup file scripts/fail-on-console.ts turns any console.log in library code into a test failure.

Formatting and linting are Biome, wired through convenience scripts:

pnpm fix          # format + lint with auto-fix
pnpm check:circular   # madge circular-dependency check over packages/zod/src

Git hooks

Husky installs two hooks (see .husky/): pre-commit runs pnpm check:semver and lint-staged (Biome over staged files), and pre-push runs pnpm check:semver and the full pnpm test. Both abort if untracked files are present. Never bump the version in packages/zod/package.json — a version bump pushed to main is what triggers a release.

Your first change

CONTRIBUTING.md asks that you open an issue describing the change before building it. A well-scoped first contribution:

  1. A locale fix is the classic low-risk change: each file in packages/zod/src/v4/locales/ (52 of them, ar.ts through zh-TW.ts) exports a single localeError map. Fixing a translation touches one self-contained file, and there are existing per-locale tests to copy (packages/zod/src/v4/classic/tests/locales_ka.test.ts).
  2. A missing test is even safer. Test files live in packages/zod/src/v4/classic/tests/ (80 files, one per feature area). Pick the file matching the behavior, add a focused test(...) block, and run just that file.

Reproduce the behavior in play.ts first, then encode it as a test. Features without tests are considered incomplete in this repo.

Where next

Sources: package.json, pnpm-workspace.yaml, CONTRIBUTING.md, AGENTS.md, .husky/* · last synced 2026-08-10 · 2d90846 · version 4.4.3