React Hook Form Resolvers: One Resolver Interface for 20 Schema Libraries
Validation resolvers: Yup, Zod, Superstruct, Joi, Vest, Class Validator, io-ts, Nope, computed-types, typanion, Ajv, TypeBox, ArkType, Valibot, effect-ts, VineJS and Standard Schema.
At a glance
- What is it?
- @hookform/resolvers is the adapter layer that lets react-hook-form delegate validation to Yup, Zod, Joi, Ajv, Valibot and more. It is a thin package with a wide compatibility matrix, and the differences between resolvers matter more than the install command.
- Who is it for?
- Adopt @hookform/resolvers if you already keep a schema library and want react-hook-form to use it as the single source of validation truth; the per-library subpath imports keep the bundle from pulling in adapters you never call. Skip it if your forms are small enough that register-level rules cover them, or if you need multi-error reporting from a resolver whose row in the comparison table shows only firstError.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 14 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 27, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem is duplication between form state and schema validation
A react-hook-form form can validate on its own. Each input gets register options with required, min, max, pattern and a validate callback. That works until the same rules already exist somewhere else: a Zod schema shared with an API route, a Yup schema reused on the server, a class-validator DTO that the backend also enforces. At that point the form rules and the schema drift, and the drift shows up as a client that accepts what the server rejects.
@hookform/resolvers removes that duplication. The package description states its goal directly: use any external validation library such as Yup, Zod, Joi, Vest, Ajv and many others, and if you are not using a library you can write your own logic. The audience is therefore teams that already committed to a schema library and want the form to be a consumer of that schema rather than a second copy of it. If your validation lives only in the form, this package adds a dependency and an indirection for nothing.
How a resolver plugs into react-hook-form's validation loop
react-hook-form's useForm accepts a resolver prop. Instead of walking register options field by field, the form hands the current values to the resolver, and the resolver returns errors in the shape react-hook-form expects. The resolver is the only piece that knows about your schema library; the form does not.
The API is uniform across libraries. The README gives the signature as resolver(schema, schemaOptions?, resolverOptions?), where schema is required, schemaOptions is passed through to the validation library, and resolverOptions carries mode ('async' or 'sync', with async as the default) and a raw flag. That uniformity is the whole value proposition: swapping yupResolver for zodResolver is a one-line change at the call site, not a rewrite of every field.
What differs is what each adapter can do. The comparison table in the README lists two columns. Infer values from schema is true for ArkType, class-validator, computed-types, Effect, io-ts, Standard Schema, Superstruct, typanion, TypeBox, Valibot, VineJS, Yup and Zod, and false for AJV, ata-validator, fluentvalidation-ts, Joi, Nope and TypeSchema. The criteriaMode column shows firstError for ArkType, computed-types, fluentvalidation-ts, io-ts, Nope, Standard Schema, Superstruct and typanion, and firstError | all for the rest. That second column is the one people miss. If you need every error on a field at once, a firstError-only adapter will not give it to you.
Installing @hookform/resolvers and wiring a Zod form
The README lists four package managers. The validation library is installed alongside the resolvers package, not bundled with it.
npm install @hookform/resolversThe same section gives yarn add @hookform/resolvers, pnpm install @hookform/resolvers and bun install @hookform/resolvers as equivalents. Because the package publishes per-library subpaths, you import only the adapter you use. The package.json exports map shows ./zod, ./yup, ./joi, ./vest, ./superstruct, ./typebox and others, each with its own import, require, umd and types entries resolving into a per-library dist folder.
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod'; // or 'zod/v4'
const schema = z.object({
name: z.string().min(1, { message: 'Required' }),
age: z.number().min(10),
});
const App = () => {
const { register, handleSubmit, formState: { errors } } = useForm({
resolver: zodResolver(schema),
});
return (
<form onSubmit={handleSubmit((d) => console.log(d))}>
<input {...register('name')} />
{errors.name?.message && <p>{errors.name.message}</p>}
</form>
);
};That is the README's Zod quickstart, trimmed to the essentials. After wiring it, submitting an empty name should render the Required paragraph, because the message is attached to the schema rule rather than to the input. The README notes the example uses valueAsNumber, which requires react-hook-form v6.12.0 or later. It also warns that if your schema uses .default(...) on a field, that field becomes optional on z.input but stays required on z.output, so passing a single generic to useForm<T> pins both and conflicts with zodResolver's inference. The documented fix is the three-generic form: useForm<z.input<typeof schema>, any, z.output<typeof schema>>.
Context, generics and the places the abstraction leaks
The Yup section carries a warning that is easy to skip and expensive to debug. Pass context through useForm({ context }), not through yupResolver's schemaOptions, because schemaOptions.context is overridden by the form context. The README shows yupResolver(schema, { context: { foo: true } }) under an "Avoid" comment. A team that reads only the resolver signature will write the second form and wonder why conditional Yup tests never see the flag.
Type inference is the other leak. The README's TypeScript section states that most resolvers can infer the output type from the schema, not all. The comparison table is the authority: six of the listed adapters do not infer values from the schema at all. With those, you supply the form's value type yourself, and a schema change that alters a field's type will not surface as a compile error at the useForm call.
criteriaMode is the third. A resolver marked firstError will surface one error per field regardless of how many rules fail. If your UI renders a list of messages under each input, you are choosing the wrong adapter unless you switch libraries. None of this is a defect in the package; it is the cost of normalizing twenty different error models into one interface, and the README's table is honest about which adapters lose information in the process.
When a plain register rule beats pulling in a resolver
The wrong tool case is a small form with no shared schema. A login form with an email pattern and a required password does not need Zod, a resolver, and the generic plumbing that comes with inferring input and output types. register options express that in a few lines and keep the component's types simple.
The second wrong-tool case is a team that wants multi-error reporting per field and has standardized on a firstError-only library. The fix is not a resolver configuration; the table says the adapter does not support firstError | all, so the choice is to change validation libraries or to accept one message per field. Changing the resolver will not change that outcome.
The third is a project that has not yet picked a schema library. @hookform/resolvers is an adapter, not a validator. It has no schema language of its own, and installing it before choosing Zod, Yup, Valibot or another library gets you a package with nothing to resolve.
Valibot and Standard Schema as alternatives to a library-specific resolver
The obvious alternative is not another adapter but a different layer. Standard Schema is a specification for validation libraries to expose a common interface, and this repository ships a standard-schema adapter. The difference in approach is real: instead of importing zodResolver or valibotResolver and binding your form to that library's adapter, you import the Standard Schema resolver and pass any schema that implements the spec. The README's table lists Standard Schema with inference supported and criteriaMode firstError | all.
The trade-off is coverage. A library-specific adapter can expose options that the generic interface has no place for, which is exactly why the Yup context warning exists. Standard Schema buys portability across libraries that implement the spec and gives up library-specific escape hatches. If your team is confident it will stay on one schema library, the specific adapter is the safer default; if you are hedging, the Standard Schema path is the one that survives a swap. Valibot and ArkType both appear in the table with inference and firstError | all, so they are viable targets either way.
Maintenance, licensing and what an upgrade actually costs
The repository is not archived, and the last push was on 2026-08-17, the same day as the v5.9.1 release. The three most recent releases are v5.9.1 on 2026-08-17, v5.9.0 on 2026-08-15 and v5.8.0 on 2026-08-13, so the recent cadence is dense. The package.json in the repository still declares version 5.3.0 while the release list shows 5.9.1, which is a normal lag between the working tree and published tags rather than a signal about stability.
The upgrade cost is mostly your validation library's, not this package's. The resolvers are thin adapters, so a major version of Zod or Yup is what breaks your schemas. Two things in this repository do change under you: the exports map, which determines whether @hookform/resolvers/zod resolves under your bundler's exports handling, and the TypeScript inference behavior described in the README, which is where the .default(...) warning lives. Pin the package and read the release notes on a major bump.
The licence is MIT, which permits commercial and private use and modification with the licence and copyright notice preserved. That is a statement about the licence text, not advice about your situation; if you redistribute the package, read the LICENSE file in the repository rather than a summary.
Editorial conclusion
Adopt @hookform/resolvers if you already keep a schema library and want react-hook-form to use it as the single source of validation truth; the per-library subpath imports keep the bundle from pulling in adapters you never call. Skip it if your forms are small enough that register-level rules cover them, or if you need multi-error reporting from a resolver whose row in the comparison table shows only firstError. Before committing, verify three things in your own setup: that your schema library appears in the comparison table with the criteriaMode you need, that your generic arguments to useForm match the resolver's inferred input and output types, and that the resolver subpath you import resolves under your bundler's exports handling.
Frequently asked questions
How do I install @hookform/resolvers?
Install it with npm install @hookform/resolvers, or the yarn, pnpm and bun equivalents the README lists. Install your validation library alongside it, since the resolvers package does not bundle one.
How do I install the Zod resolver for @hookform/resolvers?
Install @hookform/resolvers and zod, then import { zodResolver } from '@hookform/resolvers/zod' and pass zodResolver(schema) as the resolver prop to useForm. The README's Zod quickstart shows the full component.
How do I install the Yup resolver for @hookform/resolvers?
Install @hookform/resolvers and yup, then import { yupResolver } from '@hookform/resolvers/yup'. The README warns to pass context via useForm({ context }) rather than through yupResolver's schemaOptions, because schemaOptions.context is overridden by the form context.
What are resolvers used for in @hookform/resolvers?
They let react-hook-form delegate validation to an external schema library instead of per-field register options, so the schema stays the single source of validation rules. The README states the goal is to integrate whichever validation library you prefer, and that you can write your own logic if you are not using one.
What are the different types of resolvers in @hookform/resolvers?
The README's comparison table lists AJV, ata-validator, ArkType, class-validator, computed-types, Effect, fluentvalidation-ts, io-ts, Joi, Nope, Standard Schema, Superstruct, typanion, TypeBox, TypeSchema, Valibot, Vest, VineJS, Yup and Zod. Each has its own subpath import and its own support for schema inference and criteriaMode.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/react-hook-form-resolvers)