From 8539538135add9c9429cd93d5b3084309ffd5231 Mon Sep 17 00:00:00 2001 From: Yaroslav Slepukhin Date: Thu, 30 Jul 2026 11:07:33 +0200 Subject: [PATCH 1/2] feat: add Yup replacements --- docs/modules/yup.md | 61 ++++++++++++++++++++++++++++++++++++++++ manifests/preferred.json | 16 +++++++++++ 2 files changed, 77 insertions(+) create mode 100644 docs/modules/yup.md diff --git a/docs/modules/yup.md b/docs/modules/yup.md new file mode 100644 index 00000000..3fd0a6ef --- /dev/null +++ b/docs/modules/yup.md @@ -0,0 +1,61 @@ +--- +description: Modern alternatives to the yup package for TypeScript schema validation +--- + +# Replacements for `yup` + +[`valibot`](https://valibot.dev/) and [`zod/mini`](https://zod.dev/packages/mini) are modular, tree-shakable alternatives to `yup`. Both support [Standard Schema](https://standardschema.dev/), allowing them to work with schema-agnostic integrations. See [Schema Benchmarks](https://schemabenchmarks.dev/download) for current comparisons of schema library bundle sizes and runtime behavior. + +## `valibot` + +Valibot uses a functional API. Its [migration guide](https://valibot.dev/guides/migrate-from-yup/) covers the complete mapping from Yup APIs. + + +```ts +import * as yup from 'yup' // [!code --] +import * as v from 'valibot' // [!code ++] + +const schema = yup.object({ // [!code --] + name: yup.string().required(), // [!code --] + age: yup.number().min(0).required() // [!code --] +}) // [!code --] + +const schema = v.object({ // [!code ++] + name: v.pipe(v.string(), v.nonEmpty()), // [!code ++] + age: v.pipe(v.number(), v.minValue(0)) // [!code ++] +}) // [!code ++] + +const value = await schema.validate(input) // [!code --] +const value = v.parse(schema, input) // [!code ++] +``` + +Yup schemas are optional by default, whereas Valibot schemas are required by default. `yup.string().required()` also rejects an empty string, so use `v.nonEmpty()` when preserving that behavior. Validation chains become `v.pipe(...)` calls, and `v.parse` is synchronous; use `v.parseAsync` for asynchronous validation. + +Yup casts input before validation and preserves unknown object keys by default. 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 yup from 'yup' // [!code --] +import * as z from 'zod/mini' // [!code ++] + +const schema = yup.object({ // [!code --] + name: yup.string().required(), // [!code --] + age: yup.number().min(0).required() // [!code --] +}) // [!code --] + +const schema = z.object({ // [!code ++] + name: z.string().check(z.minLength(1)), // [!code ++] + age: z.number().check(z.gte(0)) // [!code ++] +}) // [!code ++] + +const value = await schema.validate(input) // [!code --] +const value = schema.parse(input) // [!code ++] +``` + +Zod Mini schemas are required by default; wrap optional fields with `z.optional(...)`. Its functional checks replace Yup's chained validation methods, 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. diff --git a/manifests/preferred.json b/manifests/preferred.json index 495dc852..655a049c 100644 --- a/manifests/preferred.json +++ b/manifests/preferred.json @@ -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": "yup"} } }, "replacements": { @@ -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", @@ -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" } } } From e86157750941002262949e2aa6c1ed709eb32665 Mon Sep 17 00:00:00 2001 From: Yaroslav Slepukhin Date: Thu, 30 Jul 2026 21:53:07 +0200 Subject: [PATCH 2/2] docs: generalize schema validation guide --- docs/modules/schema-validation.md | 49 +++++++++++++++++++++++++ docs/modules/yup.md | 61 ------------------------------- manifests/preferred.json | 2 +- 3 files changed, 50 insertions(+), 62 deletions(-) create mode 100644 docs/modules/schema-validation.md delete mode 100644 docs/modules/yup.md diff --git a/docs/modules/schema-validation.md b/docs/modules/schema-validation.md new file mode 100644 index 00000000..07d3b90a --- /dev/null +++ b/docs/modules/schema-validation.md @@ -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. diff --git a/docs/modules/yup.md b/docs/modules/yup.md deleted file mode 100644 index 3fd0a6ef..00000000 --- a/docs/modules/yup.md +++ /dev/null @@ -1,61 +0,0 @@ ---- -description: Modern alternatives to the yup package for TypeScript schema validation ---- - -# Replacements for `yup` - -[`valibot`](https://valibot.dev/) and [`zod/mini`](https://zod.dev/packages/mini) are modular, tree-shakable alternatives to `yup`. Both support [Standard Schema](https://standardschema.dev/), allowing them to work with schema-agnostic integrations. See [Schema Benchmarks](https://schemabenchmarks.dev/download) for current comparisons of schema library bundle sizes and runtime behavior. - -## `valibot` - -Valibot uses a functional API. Its [migration guide](https://valibot.dev/guides/migrate-from-yup/) covers the complete mapping from Yup APIs. - - -```ts -import * as yup from 'yup' // [!code --] -import * as v from 'valibot' // [!code ++] - -const schema = yup.object({ // [!code --] - name: yup.string().required(), // [!code --] - age: yup.number().min(0).required() // [!code --] -}) // [!code --] - -const schema = v.object({ // [!code ++] - name: v.pipe(v.string(), v.nonEmpty()), // [!code ++] - age: v.pipe(v.number(), v.minValue(0)) // [!code ++] -}) // [!code ++] - -const value = await schema.validate(input) // [!code --] -const value = v.parse(schema, input) // [!code ++] -``` - -Yup schemas are optional by default, whereas Valibot schemas are required by default. `yup.string().required()` also rejects an empty string, so use `v.nonEmpty()` when preserving that behavior. Validation chains become `v.pipe(...)` calls, and `v.parse` is synchronous; use `v.parseAsync` for asynchronous validation. - -Yup casts input before validation and preserves unknown object keys by default. 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 yup from 'yup' // [!code --] -import * as z from 'zod/mini' // [!code ++] - -const schema = yup.object({ // [!code --] - name: yup.string().required(), // [!code --] - age: yup.number().min(0).required() // [!code --] -}) // [!code --] - -const schema = z.object({ // [!code ++] - name: z.string().check(z.minLength(1)), // [!code ++] - age: z.number().check(z.gte(0)) // [!code ++] -}) // [!code ++] - -const value = await schema.validate(input) // [!code --] -const value = schema.parse(input) // [!code ++] -``` - -Zod Mini schemas are required by default; wrap optional fields with `z.optional(...)`. Its functional checks replace Yup's chained validation methods, 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. diff --git a/manifests/preferred.json b/manifests/preferred.json index 655a049c..a47204c9 100644 --- a/manifests/preferred.json +++ b/manifests/preferred.json @@ -2802,7 +2802,7 @@ "type": "module", "moduleName": "yup", "replacements": ["valibot", "zod/mini"], - "url": {"type": "e18e", "id": "yup"} + "url": {"type": "e18e", "id": "schema-validation"} } }, "replacements": {