Welcome to the Schema Benchmarks project. This aims to compare the performance of different schema validation libraries in detail, including separating each step of the process.
Benchmarks
Steps benchmarked include:
Initialization
Creating the schema itself. This is usually a one time cost.
schemas.ts
import * as v from "valibot"; export const personSchema = v.object({ name: v.string(), age: v.number(), }); export type Person = v.InferOutput<typeof personSchema>;
Validation
Checking if a given value matches the schema. Crucially, this is different to parsing because it doesn't return a new value.
import * as v from "valibot";
import { personSchema } from "./schemas";
if (v.is(personSchema, data)) {
// data is narrowed to Person
}
Some libraries only support validation (e.g.
ajv) or parsing (e.g.zod). In these cases, we categorise them accordingly.
Parsing
Checking if a given value matches the schema, and returning a new value. This will include any transformations.
import * as v from "valibot";
import { personSchema } from "./schemas";
const person = v.parse(personSchema, data);
// person is of type Person
Tags
Optimizations
Some libraries utilise specific optimizations to improve performance. We specifically track:
- JIT: Libraries that use Just-In-Time compilation (usually via
new Function) to generate optimized code at runtime, e.g.arktype - Precompiled: Libraries that generate optimized code at build time, e.g.
typia
Error handling
Some libraries support different error handling strategies. We specifically track:
- All errors: Parse the entire value before returning/throwing an error.
- Abort early: Return/throw an error as soon as an issue is found.
Download
As well as running runtime tests, we test the bundle size of each library. This is important for browser usage, where this will affect download time.