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:
"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:
- A locale fix is the classic low-risk change: each file in
packages/zod/src/v4/locales/(52 of them,ar.tsthroughzh-TW.ts) exports a singlelocaleErrormap. 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). - 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 focusedtest(...)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
- What actually happens when your test calls
.parse(): the parse pipeline. - How the classic, mini, and core layers relate: schema construction.
- What every dev dependency is for: technologies.