UISlopKiller Template

TypeScript Validation Libraries Compared: What 6 Tools Reveal About Contracts

Front-end engineer nyaomaru compares 6 TypeScript validation libraries and handwritten guards, highlighting hidden contract differences, bundle sizes, and benchmarks.

3 min readUISlopKiller

According to front-end engineer and OSS developer nyaomaru, comparing runtime validation tools in TypeScript often turns into a simple question of which library to choose. To understand what these libraries actually buy developers, nyaomaru implemented the same User validation using a handwritten guard with a TypeScript predicate, is-kit (version 1.15.3), Runtypes (version 7.0.5), Valibot (version 1.5.0), Zod (version 4.6.5), ArkType (version 2.2.8), and typia (version 15.1.0). Every library was tested against the same 35 JSON fixtures.

The hardest part of the experiment was not making seven validators compile, but making them mean the same thing. Even a simple rule like a string with at most 100 characters can describe different runtime contracts.

Before/After: The String Length Surprise

  • Before (The Default): Using built-in string length checks directly from schema libraries like Zod or typia. Because these built-in checks count Unicode code points instead of JavaScript's string.length, an emoji string like "馃榾".repeat(51)鈥攚hich totals 102 UTF-16 code units鈥攑asses validation because it consists of 51 code points.
  • After (The Fix): To enforce an exact contract of 100 UTF-16 code units, you must switch to custom refinements. For instance, Zod requires a .refine() with JavaScript's string.length, and typia requires a custom tag to preserve the stated UTF-16 rule, matching the behavior of handwritten guards, is-kit, Runtypes, Valibot, and ArkType.

Understanding the Architectural Layers

These tools solve overlapping problems at very different layers, rather than acting as a simple upgrade ladder. A handwritten guard has no extra model to learn, but maintenance scales poorly as a codebase grows. Schema libraries like Valibot offer modular function composition with tree shaking, while Zod integrates deeply with an extensive ecosystem of form handlers and API tools. Meanwhile, typia generates specialized validation code during the build using TypeScript types and tags, requiring a build transform setup (such as TypeScript 7.0.2 and ttsc 0.31.3).

Bundle Sizes and Benchmarks

When bundled with esbuild for a browser target using ESM, ES2022, minification, and tree shaking, standalone bundle outputs vary dramatically. Measured in Brotli bytes, a handwritten guard costs 295 bytes, is-kit takes 1,423 bytes, Valibot uses 1,675 bytes, Runtypes requires 4,657 bytes, regular Zod reaches 23,331 bytes, and ArkType takes 41,956 bytes. typia's final guard bundle was just 339 Brotli bytes in this test, demonstrating that generated validators still ship a small footprint.

Steady-state runtime benchmarks conducted across 20,000 warmup calls and 50,000 measured calls per sample showed median nanoseconds per call varying significantly by failure path and architecture. Ultimately, as nyaomaru notes, you should use the smallest model that represents your boundary well, keeping in mind that equivalent-looking schemas are not automatically equivalent runtime contracts.

Photo by Christina Morillo, CC0 1.0, via Openverse

Sources