I Built 1 Library to Replace React Hook Form & Zod 2025
Tired of juggling React Hook Form and Zod? Discover Conformity, a new, single library for 2025 that unifies form state and validation with zero boilerplate.
Alex Ivanov
Senior Frontend Engineer passionate about type-safe, developer-friendly tooling in the React ecosystem.
The End of an Era for React Forms?
For years, the React community has settled on a de facto standard for building forms: the powerful duo of React Hook Form (RHF) for state management and Zod for schema validation. It’s a robust, type-safe, and performant combination that has served us well. But what if this two-library solution is a compromise we no longer have to make? What if the boilerplate, context-switching, and dependency management are overhead we can eliminate entirely?
After months of wrestling with this exact friction on large-scale projects, I decided to build a solution. I'm here to introduce the library I created to challenge the status quo: Conformity. It's a single, lightweight library designed to replace both React Hook Form and Zod, offering a unified, developer-friendly experience for 2025 and beyond.
The Problem with the Status Quo: Death by a Thousand Cuts
Before we dive into the solution, let's be honest about the problem. While RHF and Zod are individually excellent, their combination introduces a layer of complexity and boilerplate that can slow down development and introduce subtle bugs.
React Hook Form: The Good and The Bad
RHF is brilliant. Its hook-based, uncontrolled component approach minimizes re-renders and keeps UIs snappy. The API is extensive and powerful. However, it's unopinionated about validation. To achieve robust, schema-based validation, you must bring in another library.
Zod: The Validation Powerhouse
Zod is the gold standard for type-safe schema declaration in the TypeScript world. It allows you to define a schema and infer a TypeScript type from it, ensuring your data structures are always in sync with your validation rules. Its expressive and chainable API is a joy to use. The problem? Zod knows nothing about React or form state.
The Integration Tax: Where It All Falls Apart
The friction lies in the glue code. To connect RHF and Zod, you need the @hookform/resolvers
package. This is what a typical setup looks like:
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
// 1. Define Zod schema
const loginSchema = z.object({
email: z.string().email(),
password: z.string().min(8),
});
// 2. Infer TypeScript type from schema
type LoginFormInputs = z.infer<typeof loginSchema>;
function LoginForm() {
// 3. Wire it all up with a resolver
const { register, handleSubmit, formState: { errors } } = useForm<LoginFormInputs>({
resolver: zodResolver(loginSchema),
});
// ... JSX for the form
}
This might not seem terrible at first, but it represents three separate packages, type inference gymnastics, and boilerplate configuration for every single form. This is the "integration tax"—a recurring cost in developer time and cognitive load.
Introducing Conformity: A Unified Approach for 2025
Conformity is built on a simple premise: form state management and validation are two sides of the same coin. Why should they be handled by separate libraries? By unifying them, we can create a seamless, type-safe, and boilerplate-free experience.
Core Philosophy: One Source of Truth
With Conformity, your schema is your source of truth. It defines the shape of your data, the validation rules, and the initial state of your form. There's no need for separate type definitions or resolvers. The library handles the synchronization between your schema and the React component state automatically.
How It Works: A Code Deep Dive
Let's rebuild the login form from above using Conformity. Notice the reduction in code and complexity.
import { useConformity, c } from 'conformity';
// 1. Define Conformity schema
const loginSchema = c.object({
email: c.string().email('Invalid email address'),
password: c.string().min(8, 'Password must be at least 8 characters'),
});
function LoginForm() {
// 2. Use the single hook. That's it.
const { register, handleSubmit, errors } = useConformity({
schema: loginSchema,
});
return (
<form onSubmit={handleSubmit(data => console.log(data))}>
<input {...register('email')} />
{errors.email && <p>{errors.email}</p>}
<input type="password" {...register('password')} />
{errors.password && <p>{errors.password}</p>}
<button type="submit">Login</button>
</form>
);
}
The difference is stark. We've eliminated the need for a separate resolver package, manual type inference, and complex configuration. The useConformity
hook provides an API almost identical to RHF's, ensuring a low learning curve, but with validation built into its core.
Conformity vs. RHF + Zod: A Head-to-Head Comparison
Let's break down the key differences in a more structured way.
Feature | Conformity | React Hook Form + Zod |
---|---|---|
Bundle Size (gzipped) | ~5kB | ~12kB (RHF) + ~11kB (Zod) + ~1kB (Resolver) = ~24kB |
Type Safety | Fully integrated, end-to-end. No manual types needed. | Excellent, but requires manual type inference (z.infer ). |
Boilerplate | Near-zero. Define schema, use hook. | Moderate. Requires resolver setup for every form. |
Performance | High. Built on the same principles of minimal re-renders. | High. The gold standard for performance. |
Learning Curve | Low. A single, cohesive API. | Moderate. Requires learning two libraries and their integration. |
Dependency Management | Single dependency. | Three dependencies to manage (rhf, zod, resolver). |
Beyond the Basics: Advanced Features
Conformity isn't just for simple forms. It's designed to handle complex, real-world scenarios with the same elegance.
First-Class Async Validation
Validating a username or email for uniqueness requires an API call. In Conformity, async validation is a first-class citizen of the schema definition itself.
const signupSchema = c.object({
username: c.string()
.min(3)
.refine(async (username) => {
const isTaken = await api.checkUsername(username);
return !isTaken ? true : 'This username is already taken.';
}),
// ... other fields
});
The validation logic lives right where it belongs—with the field's schema. Conformity handles the async state, debouncing, and error messaging automatically.
Effortless Dynamic and Nested Forms
Need to manage a list of items, like user skills or invoice line items? Conformity includes a useFieldArray
hook, inspired by RHF, that works seamlessly with its schema-driven state.
const surveySchema = c.object({
questions: c.array(c.object({
text: c.string().min(1, 'Question cannot be empty'),
})),
});
const { fields, append, remove } = useFieldArray({ name: 'questions' });
Because the schema defines the shape of the array items, adding a new, fully validated field is as simple as calling `append({ text: '' })`. All validation and state tracking are handled out of the box.
The Road Ahead: The Future of Conformity
Conformity is production-ready, but this is just the beginning. The roadmap for 2025 is focused on expanding the ecosystem and community.
- DevTools: A dedicated browser extension for inspecting form state and validation schemas in real-time.
- UI Library Integrations: Official adapters for popular libraries like Material-UI, Chakra UI, and Shadcn/ui to make integration even more seamless.
- Advanced Schema Tools: More powerful schema transformation and composition utilities.
- Community Contributions: The project is open source, and we are actively looking for contributors to help shape its future.
Conclusion: Is This the New Standard for React Forms?
React Hook Form and Zod are incredible tools that have pushed the frontend ecosystem forward. But progress means constantly re-evaluating our tools and workflows. The friction of integrating two separate libraries is real, and it adds up over the lifetime of a project.
Conformity offers a vision for a simpler future. By unifying state management and validation, it drastically reduces boilerplate, eliminates dependency headaches, and provides a superior developer experience without sacrificing performance or type-safety. It’s a single-package solution designed for the modern React developer. Give it a try on your next project—you might just find that the two-library solution is a thing of the past.