Formify: type-safe validation without the boilerplate
Cerebrix — Development Collective
Validation libraries are either bloated or full of magic. Formify is neither: zero dependencies, full type inference, and one schema that works on the client and the server. Here's how it actually feels to use.
Most form validation setups share the same shape: a schema library, a runtime dependency tree, and a types file that drifts from both. Formify collapses that into a single dependency-free module where the schema itself is the type.
One schema, everywhere
The same schema you use to validate a signup form on the client validates the request body on your server. No duplication, no drift — the types flow straight from the schema into your editor.
import { schema, string, email, number } from "formify";
const user = schema({
name: string(),
email: email(),
age: number().min(18),
});
const result = user.validate(input);
// result.data is fully typed — no annotations needed
Reading the result
Validation returns a result, not a throw. That means you decide what happens next — render errors in the UI, return a 400 from an API, or both — with the same shape on both sides:
if (!result.success) {
// result.errors is a readable list, ready for your form
return res.status(400).json({ errors: result.errors });
}
// result.data is your validated, typed value
createUser(result.data);
Error messages are written for humans: "email must be a valid email address", not opaque codes. Map them straight into your form fields and you're done.
Custom rules are just functions
No plugin system, no inheritance dance. A rule is a function, so your domain logic composes naturally:
import { string } from "formify";
const username = string()
.min(3)
.custom((value) =>
/^[a-z0-9_]+$/.test(value)
? null
: "usernames can only contain lowercase letters, numbers, and underscores"
);
Async rules (checking if an email is already taken) work the same way — the rule returns a promise and Formify awaits it.
Composing with any form library
Formify handles the validation layer, so it composes cleanly with whatever manages your form state. Use it to validate values before submit, or wire its errors into React Hook Form, Formik, or plain useState — the API doesn't care about your framework, and neither does the bundle.
Small by design
Formify ships with zero runtime dependencies and a footprint under 3kb. It runs in browsers, Node.js, Deno, Bun, and edge runtimes — because validation shouldn't be the reason your bundle grows.
Read the docs to define your first schema, or grab the source from the Formify page.
Have a project in mind?
We build web apps, mobile apps, and browser extensions. Let's talk about yours.