Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions docs/modules/schema-validation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
description: Modern alternatives for TypeScript schema validation
---

# TypeScript schema validation

This page contains common, recommended alternatives for TypeScript schema validation. [`valibot`](https://valibot.dev/) and [`zod/mini`](https://zod.dev/packages/mini) are modular, tree-shakable options that both support [Standard Schema](https://standardschema.dev/), allowing them to work with schema-agnostic integrations.

See [Schema Benchmarks](https://schemabenchmarks.dev/download) to explore other schema validation libraries and compare their bundle sizes and runtime behavior.

When migrating between schema libraries, verify optionality, empty-string handling, type coercion, unknown object keys, error messages, and synchronous versus asynchronous validation.

## `valibot`

Valibot uses a functional API with tree-shakable schema and validation actions.

```ts
import * as v from 'valibot'

const personSchema = v.object({
name: v.pipe(v.string(), v.nonEmpty()),
age: v.pipe(v.number(), v.minValue(0))
})

const person = v.parse(personSchema, input)
```

Valibot schemas are required by default; wrap optional fields with `v.optional(...)`. Use `v.nonEmpty()` when empty strings are invalid, and compose further checks with `v.pipe(...)`. `v.parse` is synchronous; use `v.parseAsync` for asynchronous validation.

Valibot makes transformations explicit (for example, `v.toNumber()`), and `v.object` removes unknown keys. Use `v.looseObject` when those keys need to be preserved.

## `zod/mini`

Zod Mini is the tree-shakable, functional API included with Zod 4. Install `zod@^4.0.0` and import the `zod/mini` subpath:

```ts
import * as z from 'zod/mini'

const personSchema = z.object({
name: z.string().check(z.minLength(1)),
age: z.number().check(z.gte(0))
})

const person = personSchema.parse(input)
```

Zod Mini schemas are required by default; wrap optional fields with `z.optional(...)`. Its functional checks are passed to the schema with `.check(...)`, while `parse`, `safeParse`, `parseAsync`, and `safeParseAsync` remain schema methods. As with Valibot, `z.object` strips unknown keys by default; use `z.looseObject` to preserve them.

Zod Mini does not load a default error-message locale. Configure one explicitly, for example with `z.config(z.locales.en())`, when callers depend on English error messages.
16 changes: 16 additions & 0 deletions manifests/preferred.json
Original file line number Diff line number Diff line change
Expand Up @@ -2797,6 +2797,12 @@
"moduleName": "yargs-parser",
"replacements": ["util.parseArgs", "mri"],
"url": {"type": "e18e", "id": "parseargs"}
},
"yup": {
"type": "module",
"moduleName": "yup",
"replacements": ["valibot", "zod/mini"],
"url": {"type": "e18e", "id": "schema-validation"}
}
},
"replacements": {
Expand Down Expand Up @@ -3669,6 +3675,11 @@
"nodeFeatureId": {"moduleName": "node:util", "exportName": "types"},
"url": {"type": "node", "id": "api/util.html#utiltypes"}
},
"valibot": {
"id": "valibot",
"type": "documented",
"replacementModule": "valibot"
},
"vitest": {
"id": "vitest",
"type": "documented",
Expand All @@ -3695,6 +3706,11 @@
"type": "native",
"nodeFeatureId": {"moduleName": "node:zlib", "exportName": "gzipSync"},
"url": {"type": "node", "id": "api/zlib.html#zlibgzipsyncbuffer-options"}
},
"zod/mini": {
"id": "zod/mini",
"type": "documented",
"replacementModule": "zod"
}
}
}
Loading