Clean up docs navigation and stale labels (#5901)

* docs: clean up current docs navigation

* docs: document E.164 phone numbers
This commit is contained in:
Colin McDonnell
2026-04-29 16:40:35 -07:00
committed by GitHub
parent b825c869f7
commit 17df521cdb
12 changed files with 35 additions and 66 deletions
@@ -7,11 +7,6 @@ import {
} from "fumadocs-ui/layouts/docs/sidebar";
const Tags: Record<string, string> = {
"/packages/core": "New",
"/packages/mini": "New",
"/json-schema": "New",
"/metadata": "New",
"/codecs": "New",
"/packages/v3": "Legacy",
};
export const SidebarItem = ({
+25 -25
View File
@@ -248,6 +248,7 @@ z.uuid();
z.url();
z.httpUrl(); // http or https URLs only
z.hostname();
z.e164(); // E.164 phone numbers
z.emoji(); // validates a single emoji character
z.base64();
z.base64url();
@@ -389,6 +390,19 @@ new URL("HTTP://ExAmPle.com:80/./a/../b?X=1#f oo").href
// => "http://example.com/b?X=1#f%20oo"
```
### Phone numbers
To validate phone numbers in E.164 format:
```ts
const phone = z.e164();
phone.parse("+15555555555"); // ✅
phone.parse("555-555-5555"); // ❌
```
This schema validates strings with a leading `+`, a non-zero country code, and 7 to 15 digits total.
### ISO datetimes
As you may have noticed, Zod string includes a few date/time related validations. These validations are regular expression based, so they are not as strict as a full date/time library. However, they are very convenient for validating user input.
@@ -605,7 +619,7 @@ myFormat.parse("invalid input!");
## Template literals
> **New** — Introduced in `[email protected]`.
> Introduced in `[email protected]`.
To define a template literal schema:
@@ -837,7 +851,7 @@ FishEnum.parse(2); // => ❌
```
<Callout>
**Zod 4** — This replaces the `z.nativeEnum()` API in Zod 3.
Use `z.enum()` for externally declared TypeScript enums. The `z.nativeEnum()` API is deprecated.
Note that using TypeScript's `enum` keyword is [not recommended](https://www.totaltypescript.com/why-i-dont-like-typescript-enums).
</Callout>
@@ -915,9 +929,9 @@ const SalmonAndTroutOnly = FishEnum.extract(["Salmon", "Trout"]);
## Stringbools [#stringbool]
> **💎 New in Zod 4**
> Introduced in `[email protected]`.
In some cases (e.g. parsing environment variables) it's valuable to parse certain string "boolish" values to a plain `boolean` value. To support this, Zod 4 introduces `z.stringbool()`:
In some cases (e.g. parsing environment variables) it's valuable to parse certain string "boolish" values to a plain `boolean` value. Use `z.stringbool()` for this:
```ts
const strbool = z.stringbool();
@@ -1762,20 +1776,6 @@ const MyResult = z.discriminatedUnion("status", [
Each option should be an *object schema* whose discriminator prop (`status` in the example above) corresponds to some literal value or set of values, usually `z.enum()`, `z.literal()`, `z.null()`, or `z.undefined()`.
{/*
<Callout>
In Zod 3, you were required to specify the discriminator key as the first argument. This is no longer necessary, as Zod can now automatically detect the discriminator key.
```ts
const MyResult = z.discriminatedUnion("status", [
z.object({ status: z.literal("success"), data: z.string() }),
z.object({ status: z.literal("failed"), error: z.string() }),
]);
```
If Zod can't find a discriminator key, it will throw an error at schema creation time.
</Callout> */}
<Accordions type="single">
<Accordion title="Nesting discriminated unions">
@@ -1861,7 +1861,7 @@ const Person = z.record(Keys, z.string());
// { id: string; name: string; email: string }
```
**New** — As of v4.2, Zod properly supports numeric keys inside records in a way that more closely mirrors TypeScript itself. A `number` schema, when used as a record key, will validate that the key is a valid "numeric string". Additional numerical constraints (min, max, step, etc.) will also be validated.
Zod supports numeric keys inside records in a way that closely mirrors TypeScript itself. A `number` schema, when used as a record key, will validate that the key is a valid "numeric string". Additional numerical constraints (min, max, step, etc.) will also be validated.
```ts
const numberKeys = z.record(z.number(), z.string());
@@ -1888,7 +1888,7 @@ intKeys.parse({
<Callout>
**Zod 4** — In Zod 4, if you pass a `z.enum` as the first argument to `z.record()`, Zod will exhaustively check that all enum values exist in the input as keys. This behavior agrees with TypeScript:
If you pass a `z.enum` as the first argument to `z.record()`, Zod will exhaustively check that all enum values exist in the input as keys. This behavior agrees with TypeScript:
```ts
type MyRecord = Record<"a" | "b", string>;
@@ -1896,7 +1896,7 @@ intKeys.parse({
const myRecord: MyRecord = { a: "foo" }; // ❌ missing required key `b`
```
In Zod 3, exhaustiveness was not checked. To replicate the old behavior, use `z.partialRecord()`.
For partial key sets, use `z.partialRecord()`.
</Callout>
@@ -2005,7 +2005,7 @@ fileSchema.check(
## Promises
<Callout type="warn">
**Deprecated** — `z.promise()` is deprecated in Zod 4. There are vanishingly few valid uses cases for a `Promise` schema. If you suspect a value might be a `Promise`, simply `await` it before parsing it with Zod.
**Deprecated** — `z.promise()` is deprecated. There are vanishingly few valid uses cases for a `Promise` schema. If you suspect a value might be a `Promise`, simply `await` it before parsing it with Zod.
</Callout>
<Accordions type="single"><Accordion title="See z.promise() documentation">
@@ -2531,7 +2531,7 @@ const UniqueStringArray = z.array(z.string()).check((ctx) => {
## Codecs
> **New** — Introduced in Zod 4.1. Refer to the dedicated [Codecs](/codecs) page for more information.
> Introduced in `zod@4.1`. Refer to the dedicated [Codecs](/codecs) page for more information.
Codecs are a special kind of schema that implement *bidirectional transformations* between two other schemas.
@@ -2918,7 +2918,7 @@ const Cat = z.object({ name: z.string() }).brand<"Cat">();
type Cat = z.output<typeof Cat>; // { name: string } & z.$brand<"Cat">
```
With this brand, any plain (unbranded) data structures are no longer assignable to the inferred type. You have to parse some data with the schema to get branded data.
With this brand, plain (unbranded) data structures are not assignable to the inferred type. You have to parse some data with the schema to get branded data.
> Note that branded types do not affect the runtime result of `.parse`. It is a static-only construct.
@@ -2961,7 +2961,7 @@ type ReadonlyUser = z.infer<typeof ReadonlyUser>;
</Tab>
</Tabs>
The inferred type of the new schemas will be marked as `readonly`. Note that in TypeScript, this only affects objects, arrays, tuples, `Set`, and `Map`:
The inferred type is marked as `readonly`. Note that in TypeScript, this only affects objects, arrays, tuples, `Set`, and `Map`:
<Tabs groupId="lib" items={["Zod", "Zod Mini"]}>
<Tab value="Zod">
+3 -3
View File
@@ -6,7 +6,7 @@ description: "Bidirectional transformations with encode and decode"
import { Tabs, Tab } from 'fumadocs-ui/components/tabs';
import { ThemedImage } from "@/components/themed-image";
> ✨ **New** — Introduced in `[email protected]`
> Introduced in `[email protected]`.
All Zod schemas can process inputs in both the forward and backward direction:
@@ -188,7 +188,7 @@ stringToDate.encode(new Date("2024-01-15"));
### Pipes
> **Fun fact** — Codecs are actually implemented internally as *subclass* of pipes that have been augmented with "interstitial" transform logic.
> **Fun fact** — Codecs are implemented internally as *subclasses* of pipes with "interstitial" transform logic.
During regular decoding, a `ZodPipe<A, B>` schema will first parse the data with `A`, then pass it into `B`. As you might expect, during encoding, the data is first encoded with `B`, then passed into `A`.
@@ -310,7 +310,7 @@ z.encode(successSchema, true);
Below are implementations for a bunch of commonly-needed codecs. For the sake of customizability, these are not included as first-class APIs in Zod itself. Instead, you should copy/paste them into your project and modify them as needed.
> **Note** — All of these codec implementations have been tested for correctness.
> **Note** — The codec implementations below are tested for correctness.
### `stringToNumber`
+1 -1
View File
@@ -13,7 +13,7 @@ import {
ZodUtilities,
} from "../components/ecosystem";
> **Note** — To avoid bloat and confusion, the Ecosystem section has been wiped clean with the release of Zod 4. If you've updated your library to work with Zod 4, please submit a PR to add it back in. For libraries that work with Zod 3, refer to [v3.zod.dev](https://v3.zod.dev/?id=ecosystem).
> **Note** — The Ecosystem section focuses on libraries that support Zod 4. If your library supports Zod 4, please submit a PR to add it. For libraries that work with Zod 3, refer to [v3.zod.dev](https://v3.zod.dev/?id=ecosystem).
There are a growing number of tools that are built atop or support Zod natively! If you've built a tool or library on top of Zod, let me know [on Twitter](https://x.com/colinhacks) or [start a Discussion](https://github.com/colinhacks/zod/discussions). I'll add it below and tweet it out.
@@ -141,10 +141,6 @@ The `error` param optionally accepts a function. An error customization function
z.string({ error: ()=>`[${Date.now()}]: Validation failure.` });
```
<Callout>
**Note** — In Zod v3, there were separate params for `message` (a string) and `errorMap` (a function). These have been unified in Zod 4 as `error`.
</Callout>
The error map receives a context object you can use to customize the error message based on the validation issue.
```ts
+1 -1
View File
@@ -112,7 +112,7 @@ This returns the following string:
## `z.formatError()`
<Callout type="warn">
This has been deprecated in favor of `z.treeifyError()`.
Deprecated. Use `z.treeifyError()` instead.
</Callout>
<Accordions>
+1 -1
View File
@@ -64,7 +64,7 @@ import { HeroLogo } from '../components/hero-logo';
<div className="mt-5 font-gray-100 mx-auto text-center pt-12">
<span className="">
Zod 4 is now stable! Read the <a rel="noopener noreferrer" href="/v4" alt="zod 4 release notes">release notes here</a>.
Zod 4 is stable. Read the <a rel="noopener noreferrer" href="/v4" alt="zod 4 release notes">release notes</a> and <a rel="noopener noreferrer" href="/v4/changelog" alt="zod 4 migration guide">migration guide</a>.
</span>
</div>
+1 -1
View File
@@ -8,7 +8,7 @@ import { Callout } from "fumadocs-ui/components/callout"
import { Accordion, Accordions } from 'fumadocs-ui/components/accordion';
<Callout icon={'💎'}>
**New** — Zod 4 introduces a new feature: native [JSON Schema](https://json-schema.org/) conversion. JSON Schema is a standard for describing the structure of JSON (with JSON). It's widely used in [OpenAPI](https://www.openapis.org/) definitions and defining [structured outputs](https://platform.openai.com/docs/guides/structured-outputs?api-mode=chat) for AI.
Introduced in `[email protected]`, Zod supports native [JSON Schema](https://json-schema.org/) conversion. JSON Schema is a standard for describing the structure of JSON (with JSON). It's widely used in [OpenAPI](https://www.openapis.org/) definitions and defining [structured outputs](https://platform.openai.com/docs/guides/structured-outputs?api-mode=chat) for AI.
</Callout>
+1 -19
View File
@@ -3,24 +3,6 @@ title: For library authors
description: "Guidelines and best practices for library authors integrating with Zod"
---
import { Callout } from "fumadocs-ui/components/callout"
<Callout title="Update — July 10th, 2025">
Zod `4.0.0` has been released on `npm`. This completes the incremental rollout process described below. To add support, bump your peer dependency to include `zod@^4.0.0`:
```json
// package.json
{
"peerDependencies": {
"zod": "^3.25.0 || ^4.0.0"
}
}
```
If you'd already implemented Zod 4 support according to the best practices described below (e.g. using the `"zod/v4/core"` subpath), then no other code changes should be necessary. This should not require a major version bump in your library.
</Callout>
This page is primarily intended for consumption by *library authors* who are building tooling on top of Zod.
@@ -45,7 +27,7 @@ Any library built on top of Zod should include `"zod"` in `"peerDependencies"`.
{
// ...
"peerDependencies": {
"zod": "^3.25.0 || ^4.0.0" // the "zod/v4" subpath was added in 3.25.0
"zod": "^3.25.0 || ^4.0.0" // "zod/v4" is available in 3.25.0+
}
}
```
-4
View File
@@ -1,10 +1,6 @@
{
"root": true,
"pages": [
"---Zod 4---",
"v4/index",
"v4/changelog",
"---Documentation---",
"index",
"basics",
+1 -1
View File
@@ -167,7 +167,7 @@ B.meta(); // => undefined
### `.describe()`
<Callout>
The `.describe()` method still exists for compatibility with Zod 3, but `.meta()` is now the recommended approach.
The `.describe()` method remains available, but `.meta()` is the recommended approach.
</Callout>
The `.describe()` method is a shorthand for registering a schema in `z.globalRegistry` with just a `description` field.
+1 -1
View File
@@ -10,7 +10,7 @@ import { Callout } from 'fumadocs-ui/components/callout';
**Note** — The docs for Zod Mini are interleaved with the regular Zod docs via tabbed code blocks. This page is designed to explain why Zod Mini exists, when to use it, and some key differences from regular Zod.
</Callout>
Zod Mini variant was introduced with the release of Zod 4. To try it:
Zod Mini is a tree-shakable variant of Zod. To try it:
```sh
npm install zod@^4.0.0