- Replace .eslintrc.cjs with eslint.config.mjs (ESLint 9 flat config)
using direct eslint-plugin-solid + @typescript-eslint/parser approach
- Add @typescript-eslint/parser to root devDependencies
- Add main/module/types top-level fields to packages/core/package.json
- Add resolve.conditions to packages/core/vite.config.ts
- Create packages/core/tsconfig.test.json for test type-checking
- Remove empty paths:{} from packages/core/tsconfig.json
290 lines
9.2 KiB
Markdown
290 lines
9.2 KiB
Markdown
[Skip to main content](https://www.pkgpulse.com/blog/zod-v4-vs-arktype-vs-typebox-vs-valibot-schema-2026#main-content)
|
|
|
|
## [TL;DR](https://www.pkgpulse.com/blog/zod-v4-vs-arktype-vs-typebox-vs-valibot-schema-2026\#tldr)
|
|
|
|
**Zod v4 remains the default for TypeScript validation — but Valibot (8KB vs Zod's 60KB) and ArkType (fastest runtime parsing) are compelling for performance-critical use cases.** TypeBox generates JSON Schema natively, making it the best choice for OpenAPI/Swagger integration. For new projects: Zod v4. For edge/bundle-size-critical: Valibot. For OpenAPI: TypeBox. For maximum runtime speed: ArkType.
|
|
|
|
## [Key Takeaways](https://www.pkgpulse.com/blog/zod-v4-vs-arktype-vs-typebox-vs-valibot-schema-2026\#key-takeaways)
|
|
|
|
- **Zod v4**: 60KB, 10M+ downloads/week, best ecosystem (react-hook-form, trpc, drizzle)
|
|
- **Valibot**: 8KB, tree-shakable, modular API, ~10x smaller than Zod
|
|
- **ArkType**: Fastest parser (3-10x faster than Zod), TypeScript syntax strings
|
|
- **TypeBox**: JSON Schema native, `Static<typeof Schema>` TypeScript types
|
|
- **Performance**: ArkType > Valibot > TypeBox > Zod (but all are "fast enough" for most apps)
|
|
- **Ecosystem**: Zod integrates with everything; others are catching up
|
|
|
|
* * *
|
|
|
|
## [Downloads](https://www.pkgpulse.com/blog/zod-v4-vs-arktype-vs-typebox-vs-valibot-schema-2026\#downloads)
|
|
|
|
| Package | Weekly Downloads | Trend |
|
|
| --- | --- | --- |
|
|
| `zod` | ~10M | ↑ Growing |
|
|
| `@sinclair/typebox` | ~6M | ↑ Growing |
|
|
| `valibot` | ~1M | ↑ Fast growing |
|
|
| `arktype` | ~200K | ↑ Growing |
|
|
|
|
* * *
|
|
|
|
## [Performance Benchmarks](https://www.pkgpulse.com/blog/zod-v4-vs-arktype-vs-typebox-vs-valibot-schema-2026\#performance-benchmarks)
|
|
|
|
```
|
|
Schema: User object with 10 fields, nested address, array of tags
|
|
|
|
Parsing 100,000 objects:
|
|
ArkType: 45ms ← Fastest
|
|
Valibot: 120ms
|
|
TypeBox: 180ms
|
|
Zod v4: 280ms (v4 is 2x faster than v3's ~580ms)
|
|
|
|
Bundle size (minified + gzipped):
|
|
Valibot: 8KB ← Smallest
|
|
ArkType: 12KB
|
|
TypeBox: 60KB (includes JSON Schema types)
|
|
Zod v4: 60KB
|
|
|
|
Type inference speed (tsc, 50-field schema):
|
|
ArkType: ~200ms
|
|
Zod v4: ~450ms
|
|
Valibot: ~600ms
|
|
TypeBox: ~300ms
|
|
```
|
|
|
|
* * *
|
|
|
|
## [Zod v4: The Default](https://www.pkgpulse.com/blog/zod-v4-vs-arktype-vs-typebox-vs-valibot-schema-2026\#zod-v4-the-default)
|
|
|
|
```typescript
|
|
// Zod v4 — new features and performance improvements:
|
|
import { z } from 'zod';
|
|
|
|
// Basic schema (same as v3):
|
|
const UserSchema = z.object({
|
|
id: z.string().cuid2(),
|
|
email: z.string().email(),
|
|
name: z.string().min(2).max(100),
|
|
age: z.number().int().min(0).max(150).optional(),
|
|
role: z.enum(['user', 'admin', 'moderator']),
|
|
tags: z.array(z.string()).max(10),
|
|
address: z.object({
|
|
street: z.string(),
|
|
city: z.string(),
|
|
country: z.string().length(2), // ISO 2-letter
|
|
}).optional(),
|
|
metadata: z.record(z.string(), z.unknown()),
|
|
createdAt: z.coerce.date(), // Auto-coerce string → Date
|
|
});
|
|
|
|
type User = z.infer<typeof UserSchema>;
|
|
|
|
// Zod v4 new: z.file() for Blob/File
|
|
const UploadSchema = z.object({
|
|
file: z.instanceof(File)
|
|
.refine(f => f.size < 5_000_000, 'Max 5MB')
|
|
.refine(f => ['image/jpeg', 'image/png', 'image/webp'].includes(f.type), 'Must be JPEG/PNG/WebP'),
|
|
caption: z.string().max(500).optional(),
|
|
});
|
|
|
|
// Zod v4 new: z.pipe() for chained transforms
|
|
const ParsedDateSchema = z
|
|
.string()
|
|
.pipe(z.coerce.date()); // string → validated Date
|
|
|
|
// Zod v4 new: z.toJSONSchema()
|
|
const jsonSchema = z.toJSONSchema(UserSchema);
|
|
// Generates standard JSON Schema — useful for OpenAPI docs
|
|
|
|
// Error formatting (v4 — cleaner):
|
|
const result = UserSchema.safeParse({ email: 'bad' });
|
|
if (!result.success) {
|
|
const errors = result.error.flatten();
|
|
// { fieldErrors: { email: ['Invalid email'] }, formErrors: [] }
|
|
}
|
|
```
|
|
|
|
* * *
|
|
|
|
## [Valibot: Bundle-Size Champion](https://www.pkgpulse.com/blog/zod-v4-vs-arktype-vs-typebox-vs-valibot-schema-2026\#valibot-bundle-size-champion)
|
|
|
|
```typescript
|
|
// Valibot — modular, tree-shakable:
|
|
import {
|
|
object, string, number, array, optional, enum_,
|
|
email, minLength, maxLength, integer, minValue, maxValue,
|
|
parse, safeParse, flatten,
|
|
type InferInput, type InferOutput,
|
|
} from 'valibot';
|
|
|
|
// Only imports what you use — tree-shaking reduces bundle to ~2-5KB for simple schemas
|
|
const UserSchema = object({
|
|
id: string([minLength(1)]),
|
|
email: string([email()]),
|
|
name: string([minLength(2), maxLength(100)]),
|
|
age: optional(number([integer(), minValue(0), maxValue(150)])),
|
|
role: enum_(['user', 'admin', 'moderator']),
|
|
tags: array(string(), [maxLength(10)]),
|
|
});
|
|
|
|
type User = InferInput<typeof UserSchema>;
|
|
|
|
// Parse (throws on error):
|
|
const user = parse(UserSchema, rawData);
|
|
|
|
// Safe parse (returns result/error):
|
|
const result = safeParse(UserSchema, rawData);
|
|
if (result.success) {
|
|
console.log(result.output);
|
|
} else {
|
|
const errors = flatten(result.issues);
|
|
// { nested: { email: ['Invalid email'] } }
|
|
}
|
|
```
|
|
|
|
```typescript
|
|
// Valibot with React Hook Form:
|
|
import { valibotResolver } from '@hookform/resolvers/valibot';
|
|
import { useForm } from 'react-hook-form';
|
|
|
|
function SignupForm() {
|
|
const { register, handleSubmit, formState: { errors } } = useForm({
|
|
resolver: valibotResolver(UserSchema),
|
|
});
|
|
|
|
return (
|
|
<form onSubmit={handleSubmit(console.log)}>
|
|
<input {...register('email')} />
|
|
{errors.email && <span>{errors.email.message}</span>}
|
|
</form>
|
|
);
|
|
}
|
|
```
|
|
|
|
* * *
|
|
|
|
## [ArkType: Fastest Runtime + TypeScript Syntax](https://www.pkgpulse.com/blog/zod-v4-vs-arktype-vs-typebox-vs-valibot-schema-2026\#arktype-fastest-runtime--typescript-syntax)
|
|
|
|
```typescript
|
|
// ArkType — TypeScript-syntax strings for schemas:
|
|
import { type } from 'arktype';
|
|
|
|
// Syntax feels like writing TypeScript:
|
|
const User = type({
|
|
id: 'string',
|
|
email: 'string.email',
|
|
name: '2 <= string <= 100', // min/max length shorthand!
|
|
age: 'number.integer | undefined',
|
|
role: '"user" | "admin" | "moderator"',
|
|
tags: 'string[] <= 10', // array with max length
|
|
createdAt: 'Date',
|
|
});
|
|
|
|
type User = typeof User.infer;
|
|
|
|
// Parse:
|
|
const result = User(rawData);
|
|
|
|
// ArkType returns morph (with parse) or error:
|
|
if (result instanceof type.errors) {
|
|
console.log(result.summary); // Human-readable error
|
|
} else {
|
|
// result is User
|
|
}
|
|
|
|
// ArkType advanced: morphs (transform)
|
|
const ParsedDate = type('string').pipe(s => new Date(s), 'Date');
|
|
|
|
// Recursive types (Zod struggles here):
|
|
const TreeNode = type({
|
|
value: 'number',
|
|
children: 'TreeNode[]', // Self-referencing!
|
|
}).describe('TreeNode'); // Named for error messages
|
|
```
|
|
|
|
* * *
|
|
|
|
## [TypeBox: JSON Schema Native](https://www.pkgpulse.com/blog/zod-v4-vs-arktype-vs-typebox-vs-valibot-schema-2026\#typebox-json-schema-native)
|
|
|
|
```typescript
|
|
// TypeBox — generates JSON Schema, used in Fastify/Hono:
|
|
import { Type, Static } from '@sinclair/typebox';
|
|
import { Value } from '@sinclair/typebox/value';
|
|
|
|
// TypeBox schema IS JSON Schema:
|
|
const UserSchema = Type.Object({
|
|
id: Type.String({ format: 'uuid' }),
|
|
email: Type.String({ format: 'email' }),
|
|
name: Type.String({ minLength: 2, maxLength: 100 }),
|
|
age: Type.Optional(Type.Integer({ minimum: 0, maximum: 150 })),
|
|
role: Type.Union([\
|
|
Type.Literal('user'),\
|
|
Type.Literal('admin'),\
|
|
Type.Literal('moderator'),\
|
|
]),
|
|
tags: Type.Array(Type.String(), { maxItems: 10 }),
|
|
});
|
|
|
|
// TypeScript type from schema:
|
|
type User = Static<typeof UserSchema>;
|
|
|
|
// Validate:
|
|
const result = Value.Check(UserSchema, rawData);
|
|
if (!result) {
|
|
const errors = [...Value.Errors(UserSchema, rawData)];
|
|
// [{ path: '/email', message: 'Expected string' }]
|
|
}
|
|
|
|
// TypeBox + Hono (validated routes with OpenAPI):
|
|
import { Hono } from 'hono';
|
|
import { describeRoute } from 'hono-openapi';
|
|
|
|
const app = new Hono();
|
|
app.post('/users',
|
|
describeRoute({
|
|
requestBody: { content: { 'application/json': { schema: UserSchema } } },
|
|
responses: { 201: { description: 'Created' } },
|
|
}),
|
|
async (c) => { /* handler */ }
|
|
);
|
|
|
|
// Export OpenAPI spec:
|
|
// app.doc('/openapi.json', { openapi: '3.0.0', info: { title: 'API', version: '1' } })
|
|
```
|
|
|
|
* * *
|
|
|
|
## [Decision Guide](https://www.pkgpulse.com/blog/zod-v4-vs-arktype-vs-typebox-vs-valibot-schema-2026\#decision-guide)
|
|
|
|
```
|
|
Use Zod v4 if:
|
|
→ Default choice — best ecosystem (react-hook-form, trpc, drizzle, next-safe-action)
|
|
→ Team already knows Zod v3 (v4 is mostly backwards compatible)
|
|
→ Need broad library compatibility
|
|
→ Bundle size is not a constraint
|
|
|
|
Use Valibot if:
|
|
→ Edge runtime / bundle size critical (<5KB budget)
|
|
→ Want tree-shakable, pay-only-for-what-you-use
|
|
→ Cloudflare Workers or similar constrained environments
|
|
|
|
Use ArkType if:
|
|
→ Parsing millions of objects (backend hot path)
|
|
→ Love TypeScript-native syntax strings
|
|
→ Need recursive types easily
|
|
→ Fastest possible validation
|
|
|
|
Use TypeBox if:
|
|
→ Building OpenAPI/Swagger documentation
|
|
→ Using Fastify (TypeBox is Fastify's native schema)
|
|
→ Need JSON Schema output for other tools
|
|
→ API validation that also generates docs
|
|
```
|
|
|
|
_Compare Zod, Valibot, ArkType, and TypeBox on [PkgPulse](https://pkgpulse.com/compare/zod-vs-valibot)._
|
|
|
|
## Comments
|
|
|
|
### The 2026 JavaScript Stack Cheatsheet
|
|
|
|
One PDF: the best package for every category (ORMs, bundlers, auth, testing, state management). Used by 500+ devs. Free, updated monthly.
|
|
|
|
Get the Free Cheatsheet |