NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
npm · #2532 most downloaded on npm
Dead simple Object schema validation
Last release 1 years ago
21 Sep 2025
Release timing varies
gaps range from 2 weeks to 9 months
Some releases are documented
notes for 30 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
12 years old
132 releases · first in 2014
One column per quarter.
lazy validation errors thrown in builders should resolve async like other validations
Nothing published for this version
Nothing published for this version
Nothing published for this version
addMethod: allow Schema without making TypeScript upset
pick and omit with excluded edges (6956ee7), closes #2097
Allow schema metadata to be strongly typed
Nothing published for this version
Nothing published for this version
make null validation errors consistent across schema
Nothing published for this version
fix array describe not including conditions (4040592), closes #1920
The types for Lazy have changes a bit, it's unlikely that this affects anyone but it is technically a breaking change.
oneOf required adding null explicitly to allowed values when using oneOf. Folks have found this confusing and unintuitive so I am deferring and adjusting the behaviorspec.optional and spec.nullable values, also accessible via describe()add originalValue to TestContext type (#1527) (fcc5ae7), closes /github.com/abnersajr/DefinitelyTyped/blob/a186d99d0c3a92424691a82130374a1b9145c7cd/types/yup/index.d.ts#L446
Merge next into master (#1547) (366f7d8), closes #1547 #1542 #1541 #1543 #1545
The builder object version of when() requires then and otherwise to be
functions (schema: Schema) => Schema.
The function version of when() has been changed to make it easier to type. values are always passed as an array and schema, and options always the second and third argument. this is no longer set to the schema instance. and all functions must return a schema to be type safe
string()
- .when('other', function (other) => {
- if (other) return this.required()
+ .when('other', ([other], schema) => {
+ return other ? schema.required() : schema
})
concat works shallowly now. Previously concat functioned like a deep merge for object, which produced confusing behavior with incompatible concat'ed schema. Now concat for objects works similar to how it works for other types, the provided schema is applied on top of the existing schema, producing a new schema that is the same as calling each builder method in order
docs: update readme
chore: update to readonly arrays and test string type narrowing
test: add boolean tests
docs: more docs
feat: allow mixed schema to specify type check
mixed schema are no longer treated as the base class for other schema types. It hasn't been for a while, but we've done some nasty prototype slinging to make it behave like it was. Now typescript types should be 1 to 1 with the actual classes yup exposes.
In general this should not affect anything unless you are extending (via addMethod or otherwise) mixed prototype.
import {
- mixed,
+ Schema,
} from 'yup';
- addMethod(mixed, 'method', impl)
+ addMethod(Schema, 'method', impl)
chore: prep work for toggling coercion
Publish v1.0.0-alpha.4
chore: docs
feat!: add json() method and remove default object/array coercion
object and array schema no longer parse JSON strings by default, nor do they return null for invalid casts.
object().json().cast('{}')
array().json().cast('[]')
to mimic the previous behavior
feat: Make Array generic consistent with others
types only, ArraySchema initial generic is the array type not the type of the array element. array<T>() is still the inner type.
Publish v1.0.0-beta.0
docs
ArraySchema initial generic is the array type not the type of the array element. array<T>() is still the inner type.null for invalid casts.object().json().cast('{}')
array().json().cast('[]')
to mimic the previous behavior
when types and API (#1542) (da74254)mixed schema are no longer treated as the base class for other schema types. It hasn't been for a while, but we've done some nasty prototype slinging to make it behave like it was. Now typescript types should be 1 to 1 with the actual classes yup exposes.In general this should not affect anything unless you are extending (via addMethod or otherwise) mixed prototype.
import {
- mixed,
+ Schema,
} from 'yup';
- addMethod(mixed, 'method', impl)
+ addMethod(Schema, 'method', impl)
when() requires then and otherwise to be
functions (schema: Schema) => Schema.when() has been changed to make it easier to type. values are always passed as an array and schema, and options always the second and third argument. this is no longer set to the schema instance. and all functions must return a schema to be type safe string()
- .when('other', function (other) => {
- if (other) return this.required()
+ .when('other', ([other], schema) => {
+ return other ? schema.required() : schema
})
https://github.com/jquense/yup/issues/1906
https://github.com/jquense/yup/issues/1906
Nothing published for this version
Fixes published artifacts for the main field
Fixes published artifacts for the main field
A larger breaking change in v1 is the assertion of optionality during cast, making previous patterns like string().nullable().required() no longer pos…
Beta 5 fixes partial and deepPartial making it work correctly with lazy schema. Specifically the optionality is added after lazy is evaluated but before any other when conditions are added. This makes it consistent with other conditional schema, where runtime conditions always supersede previous schema configuration. This allows for optional overrides if necessary.
const person = object({
name: string().required(),
age: number().required(),
legalGuardian: string().when('age', {
is: (age) => age != null && age < 18,
then: (schema) => schema.required(),
}),
});
const optionalPerson = person.partial()
person.cast({name: 'James', age: 6 }) // => TypeError legalGuardian required
// age is still required b/c it's applied after the `partial`
optionalPerson.cast({name: 'James', age: 6 }) // => TypeError legalGuardian required
This works slightly differently for lazy which have no schema to "start" with:
const config = object({
nameOrIdNumber: lazy((value) => {
if (typeof value === 'number') return number().required()
return string().required()
}),
});
const opti = config.partial()
config.cast({}) // => TypeError nameOrIdNumber is required
config.partial().cast({}) // => {}
A larger breaking change in v1 is the assertion of optionality during cast, making previous patterns like string().nullable().required() no longer possible. Generally this pattern is used when deserialized data is not valid to start, but will become valid through user input such as with an HTML form. v1 no longer allows this, but in order to make migration easier we've added an option to cast that mimics the previous behavior (not exactly but closely).
const name = string().required()
name.cast(null, { assert: 'ignore-optionality'}) // => null
We recommend updating your schema to new patterns where possible but this allows for incremental upgrades
Full Changelog: https://github.com/jquense/yup/compare/v1.0.0-beta.4...v1.0.0-beta.5
chore(deps): update all non-major dependencies by @renovate in https://github.com/jquense/yup/pull/1611
Full Changelog: https://github.com/jquense/yup/compare/v1.0.0-beta.3...v1.0.0-beta.4
Now they will no longer do that. To enable this fix we made a breaking change to the way that required is implemented.
This release fixes a bug with object().partial where required() schema we're still failing validation. Now they will no longer do that. To enable this fix we made a breaking change to the way that required is implemented.
schema.required no longer adds a test named 'required', this state can be determined via the schema spec or describe() metadatarequired directly to add their length check (this test is called required for some ease of back compat)Beta.2 adds core tuple type support, see the docs for more: https://github.com/jquense/yup#tuple
Beta.2 adds core tuple type support, see the docs for more: https://github.com/jquense/yup#tuple
…size insights (10.26kb gzipped!). The possible breaking change is around cherry picking imports, if you are cherry picking imports from yup import str…
Schema.import string from 'yup/lib/string' this will no longer work. This pattern has not been supported for a long time and could cause larger than necessary bundles.feat!: add json() method and remove default object/array coercion
ArraySchema initial generic is the array type not the type of the array element. array<T>() is still the inner type.null for invalid casts.object().json().cast('{}')
array().json().cast('[]')
to mimic the previous behavior
add originalValue to TestContext type (#1527) (fcc5ae7), closes /github.com/abnersajr/DefinitelyTyped/blob/a186d99d0c3a92424691a82130374a1b9145c7cd/ty
when types and API (#1542) (da74254)mixed schema are no longer treated as the base class for other schema types. It hasn't been for a while, but we've done some nasty prototype slinging to make it behave like it was. Now typescript types should be 1 to 1 with the actual classes yup exposes.In general this should not affect anything unless you are extending (via addMethod or otherwise) mixed prototype.
import {
- mixed,
+ Schema,
} from 'yup';
- addMethod(mixed, 'method', impl)
+ addMethod(Schema, 'method', impl)
when() has been changed to make it easier to type. values are always passed as an array and schema, and options always the second and third argument. this is no longer set to the schema instance. and all functions must return a schema to be type safe string()
- .when('other', function (other) => {
- if (other) return this.required()
+ .when('other', ([other], schema) => {
+ return other ? schema.required() : schema
})
A number of the improvements here are made possible by simplifications to yup's API and logic, this introduces a few breaking changes though most are…
Changes the object generics to store the derived type instead of the object shape. This imposes a few limitations on type accuracy at the edges, but dramatically speeds up the type processing by tsc on the command line and in editor. It also removes the need for the SchemaOf helper which worked...poorly.
Instead the ObjectSchema class accepts a plain type as its first generic:
interface Folder {
id: ObjectId,
label: string,
files?: File[]
}
- const folder: SchemaOf<Folder, ObjectId | File> = object({
- id: mixed<ObjectId>().defined(),
- label: string().defined(),
- files: array(mixed<File>().defined())
- })
+ const folder: ObjectSchema<Folder> = object({
+ id: mixed<ObjectId>().defined(),
+ label: string().defined(),
+ files: array(mixed<File>().defined())
+ })
It's a small diff, but big improvement in type accuracy and usability, especially with custom schema for class instances.
Note that the generics on the
object()factory method are still the "object shape, meaningobject<Folder>()won't work as expected. This is a compromise between the two strategies for handling generics and allows for an accurate type onobject().getDefault()
A number of the improvements here are made possible by simplifications to yup's API and logic, this introduces a few breaking changes though most are small and easily migrated from.
This is the largest, and likely most disruptive change. Prior yup allowed for patterns like:
const nullableRequiredString = string().nullable().required()
nullableRequiredString.cast(null) // -> null
nullableRequiredString.validate(null) // ValidationError("this is required and cannot be null")
This may seem unintuitive behavior (and it is) but allowed for a common client side validation case, where we want to use a single schema to parse server data, as well as validate user input. In other words, a server might return invalid "default" values that should still fail when trying to submit.
Now, nullable(), defined and required are all mutually dependent methods. Meaning string().nullable().defined().required() produces a schema where the value must be a string, and not null or undefined. The effect of this is that the type of a cast() is now accurate and the same as the type returned from validate.
Nothing published for this version
Nothing published for this version
Nothing published for this version
### Bug Fixes * dep ranges
carry over excluded edges when concating objects (5334349), closes #1423
types: Array required() and defined() will no longer return any
Nothing published for this version
Nothing published for this version
mixed() is the the base class (7f8591d), closes #1156
types: change base.default() to any
types: rm base pick/omit types as they conflict with more specific ones
### Bug Fixes * types: AnyObjectSchema anys
types: array type with lazy (ba92dfc), closes #1146
cyclical import (d5c5391), closes #1138
concat doesn't check for "unset" nullable or presence when merging meaning the nullability and presence will always be the same as the schema passed to concat(). They can be overridden if needed after concatenationimport { StringSchema, string } from 'yup'Nothing published for this version
security Fix for Prototype Pollution - huntr.dev
default() (#1119) (5dae837)To maintain the old behavior change to:
array().required().min(1)
to recreate the old behavior:
string().transform((_, input) => input != null && input.toString ? input.toString() : value);
Nothing published for this version
Nothing published for this version
Nothing published for this version
handle sparse array positions as undefined
present checks for array and strings (ecd8ebe), closes #913
@types/yup only, no function changes but the type def change is large enough that it warranted a major bump hereNothing published for this version
allow passing of function to .matches() options/message param
make schema.type and array.innerType public API's
array.ensure (94659c2), closes #343
mixed method to control required behavior (#459) (5b01f18)optional() and unknown() (#460) (51e8661)Related to https://github.com/jquense/yup/pull/147
mixed method to control required behavior (#459) (5b01f18)optional() and unknown() (#460) (51e8661)Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →