Zod vs Valibot vs ArkType: validation library 2026
Zod sudah dominate validation di TS ecosystem. Valibot 90% lebih kecil. ArkType TypeScript-first dengan syntax di-string. Saya pakai keduanya, verdict berbeda.
TL;DR
- Zod 4: Recommended sebagai default. Ecosystem terbesar, dokumentasi sempurna, battle-tested.
- Valibot: Recommended untuk bundle-size-critical (browser-first, edge function dengan size limit).
- ArkType: Watch — promising, tapi syntax less familiar untuk TS dev.
Konteks
Pakai keduanya di production:
- Zod: 5 project, semua server-side validation
- Valibot: 2 project, browser-first (form validation client)
- ArkType: 1 project eksperimen (tidak production)
Bundle size comparison
Schema simple: object dengan 5 field, mix of string, number, email, enum.
| Library | Bundle size (minified+gzipped) |
|---|---|
| Zod 4 | 12.8 KB |
| Valibot | 1.4 KB |
| ArkType | 4.2 KB |
Valibot 9x lebih kecil dari Zod. ArkType 3x lebih kecil.
Untuk server-side: bundle size tidak critical (server load once). Untuk client-side: matter untuk LCP/FID di mobile.
Syntax comparison
Zod
import { z } from 'zod';
const userSchema = z.object({
name: z.string().min(2).max(50),
email: z.string().email(),
age: z.number().int().positive().max(150),
role: z.enum(['admin', 'user', 'guest']),
phone: z.string().regex(/^08\d{8,11}$/, 'Nomor HP Indonesia tidak valid'),
});
type User = z.infer<typeof userSchema>;
const result = userSchema.safeParse(data);
if (result.success) {
console.log(result.data);
} else {
console.log(result.error.issues);
}
Valibot
import * as v from 'valibot';
const userSchema = v.object({
name: v.pipe(v.string(), v.minLength(2), v.maxLength(50)),
email: v.pipe(v.string(), v.email()),
age: v.pipe(v.number(), v.integer(), v.minValue(1), v.maxValue(150)),
role: v.picklist(['admin', 'user', 'guest']),
phone: v.pipe(v.string(), v.regex(/^08\d{8,11}$/, 'Nomor HP Indonesia tidak valid')),
});
type User = v.InferOutput<typeof userSchema>;
const result = v.safeParse(userSchema, data);
if (result.success) {
console.log(result.output);
} else {
console.log(result.issues);
}
Valibot pakai pipe + function-per-validation approach (similar to RxJS pipe). Lebih verbose dari Zod tapi bundle bisa tree-shake (cuma include validation yang Anda pakai).
ArkType
import { type } from 'arktype';
const userSchema = type({
name: 'string > 2 & < 50',
email: 'string.email',
age: 'number.integer >= 1 & <= 150',
role: "'admin' | 'user' | 'guest'",
phone: 'string.regex /^08\\d{8,11}$/',
});
type User = typeof userSchema.infer;
const result = userSchema(data);
if (result instanceof type.errors) {
console.log(result.summary);
} else {
console.log(result);
}
ArkType pakai string-based DSL. Familiar bagi TypeScript user (sintaks mirip TS type), tapi error message string-based bisa fragile.
Performance
Validation 100,000 objects (5 field each):
| Library | Time |
|---|---|
| Zod 4 | 380ms |
| Valibot | 240ms |
| ArkType | 180ms |
ArkType paling cepat (compile-time optimization). Valibot 2x lebih cepat dari Zod. Zod slowest tapi acceptable.
Untuk server validation 10-100 request/detik, semua acceptable. Untuk client form validation (1-10 validation/detik), tidak ada matter.
Yang Zod menang
Ecosystem
Zod has integration dengan:
- React Hook Form (
@hookform/resolvers/zod) - TanStack Form
- tRPC (default schema)
- Astro Action (default schema sejak v6)
- Drizzle ORM (drizzle-zod)
- OpenAPI (zod-to-openapi)
- ts-rest, ts-morph, dll
Setiap library TS yang butuh schema → support Zod first.
Mature error handling
Zod 4 errors API powerful:
const result = userSchema.safeParse(data);
if (!result.success) {
// Format error per field
result.error.format();
// Flatten ke object simple
result.error.flatten();
// Custom format
result.error.issues.map((i) => ({ path: i.path, message: i.message }));
}
Refinement & transformation
const passwordSchema = z.string()
.min(8)
.refine((s) => /\d/.test(s), { message: 'Butuh angka' })
.refine((s) => /[A-Z]/.test(s), { message: 'Butuh huruf besar' });
const dateSchema = z.string().transform((s) => new Date(s));
Valibot punya equivalent (check, transform) tapi syntax lebih verbose.
Documentation
Zod docs adalah gold standard. Cover edge case, contoh real-world, migration guide.
Yang Valibot menang
Bundle size
1.4 KB vs Zod 12.8 KB. Untuk client-side form yang pakai 3-5 validation, Valibot save 11 KB.
Untuk landing page yang LCP target < 1.5s, tiap KB matter.
Tree-shaking
Karena Valibot function-based, bundler bisa tree-shake validation yang tidak Anda pakai. Zod is monolithic — semua atau none.
// Hanya import yang Anda pakai
import { object, string, email, minLength } from 'valibot';
Final bundle Anda only includes ini, tidak number, array, union, dll yang tidak terpakai.
Edge function size
Cloudflare Workers limit 1MB compressed bundle. Untuk Workers yang berat (banyak validation + ORM + auth), saving bundle space matter.
Yang ArkType menang
Performance
2x faster than Zod karena compile-time optimization. Untuk server yang validate 10K request/detik, ini matter.
Syntax familiar bagi TS dev
'string > 2 & < 50' mirip TypeScript type. Easy to read kalau Anda already familiar dengan TS.
Type inference excellent
ArkType inference type tighter dari Zod dalam beberapa edge case (e.g., template literal type, conditional type).
Yang ArkType kurang
Syntax less mainstream
Walaupun familiar bagi TS dev, syntax DSL ini mean:
- Error message kurang clear (string parsing error vs structured error)
- Refactoring tools (VS Code rename, find references) kadang miss DSL string
- Plugin/integration ecosystem kecil
Documentation less polished
ArkType docs OK tapi tidak sekomprehensif Zod. Examples less, edge case kurang dokumentasi.
Smaller community
GitHub issues, Stack Overflow questions, blog post — Zod has 10-50x lebih banyak. Saat Anda stuck, harder to find help dengan ArkType.
Decision matrix
| Use case | Recommended |
|---|---|
| Server-side validation (API) | Zod (default) |
| Form validation client-side | Valibot |
| Edge function dengan size limit | Valibot |
| Performance-critical validation (10K+ req/s) | ArkType |
| Beginner / first validation library | Zod |
| Monorepo dengan multiple integration | Zod |
| Sole project, optimize bundle | Valibot |
Konteks Indonesia
Untuk SMB Indonesia API server: Zod adalah default safe. Integration dengan Astro Action, tRPC, Drizzle, dll smooth.
Untuk SMB Indonesia client form yang LCP critical: Valibot save 11KB. Untuk landing page yang sudah optimize lain, 11KB worth — bisa improve LCP 50-150ms di 4G connection.
Untuk SMB Indonesia high-throughput API (jarang use case): ArkType untuk performance, Zod untuk ecosystem balance.
Yang surprising
Saya thought Valibot adalah “Zod alternative untuk size purist”. Setelah pakai 2 project, saya temukan Valibot lebih cocok untuk form validation specifically karena pattern function compose work well dengan React Hook Form / TanStack Form.
Zod lebih cocok untuk API contract (server side, full schema, transformation, complex refinement).
Bisa pakai keduanya di same project: Valibot client-side, Zod server-side. Saya sudah pakai di 1 project, work fine.
Migration
Zod → Valibot
// Before (Zod)
const schema = z.object({
name: z.string().min(2),
age: z.number().int().positive(),
});
// After (Valibot)
const schema = v.object({
name: v.pipe(v.string(), v.minLength(2)),
age: v.pipe(v.number(), v.integer(), v.minValue(1)),
});
Mechanical conversion. Time: 1-2 jam untuk 20-30 schema.
Caveat: integration library (React Hook Form resolver) butuh switch dari @hookform/resolvers/zod ke @hookform/resolvers/valibot.
Verdict
Recommended:
- Zod 4 sebagai default untuk most TS project Indonesia
- Valibot untuk client-side form atau edge function
Watch:
- ArkType kalau performance jadi bottleneck (rare untuk SMB)
Konteks praktis untuk SMB yang juga butuh local presence: panduan setup GBP untuk SMB Tangerang.
Ditulis oleh Asti Larasati