{"success":true,"data":{"web":[{"url":"https://medium.com/@2nick2patel2/typescript-data-validators-at-scale-zod-valibot-superstruct-compared-177581543ac5","title":"TypeScript Data Validators at Scale: zod, valibot, superstruct ...","description":"If you just need lightweight validation inside a library with minimal opinions, superstruct is easy to embed. The “best” validator is the ...","position":1,"markdown":"[Sitemap](https://medium.com/sitemap/sitemap.xml)\n\n[Open in app](https://play.google.com/store/apps/details?id=com.medium.reader&referrer=utm_source%3DmobileNavBar&source=post_page---top_nav_layout_nav-----------------------------------------)\n\nSign up\n\n[Sign in](https://medium.com/m/signin?operation=login&redirect=https%3A%2F%2Fmedium.com%2F%402nick2patel2%2Ftypescript-data-validators-at-scale-zod-valibot-superstruct-compared-177581543ac5&source=post_page---top_nav_layout_nav-----------------------global_nav------------------)\n\n[Medium Logo](https://medium.com/?source=post_page---top_nav_layout_nav-----------------------------------------)\n\nGet app\n\n[Write](https://medium.com/m/signin?operation=register&redirect=https%3A%2F%2Fmedium.com%2Fnew-story&source=---top_nav_layout_nav-----------------------new_post_topnav------------------)\n\n[Search](https://medium.com/search?source=post_page---top_nav_layout_nav-----------------------------------------)\n\nSign up\n\n[Sign in](https://medium.com/m/signin?operation=login&redirect=https%3A%2F%2Fmedium.com%2F%402nick2patel2%2Ftypescript-data-validators-at-scale-zod-valibot-superstruct-compared-177581543ac5&source=post_page---top_nav_layout_nav-----------------------global_nav------------------)\n\n![](https://miro.medium.com/v2/resize:fill:32:32/1*dmbNkD5D-u45r44go_cf0g.png)\n\n# TypeScript Data Validators at Scale: zod, valibot, superstruct Compared\n\n## Choosing the right runtime validator when your TypeScript codebase stops being “just a project” and becomes infrastructure.\n\n[![Codastra](https://miro.medium.com/v2/resize:fill:32:32/1*IZcptplBcXPdWGYUkOqYnA.png)](https://medium.com/@2nick2patel2?source=post_page---byline--177581543ac5---------------------------------------)\n\n[Codastra](https://medium.com/@2nick2patel2?source=post_page---byline--177581543ac5---------------------------------------)\n\nFollow\n\n7 min read\n\n·\n\nDec 5, 2025\n\n25\n\n[Listen](https://medium.com/m/signin?actionUrl=https%3A%2F%2Fmedium.com%2Fplans%3Fdimension%3Dpost_audio_button%26postId%3D177581543ac5&operation=register&redirect=https%3A%2F%2Fmedium.com%2F%402nick2patel2%2Ftypescript-data-validators-at-scale-zod-valibot-superstruct-compared-177581543ac5&source=---header_actions--177581543ac5---------------------post_audio_button------------------)\n\nShare\n\nPress enter or click to view image in full size\n\n![](https://miro.medium.com/v2/resize:fit:700/1*F2GvuH0OyiTeZTN0wtdxkg.png)\n\nCompare zod, valibot, and superstruct for TypeScript data validation at scale — performance, DX, bundle size, and architecture trade-offs.\n\nYou don’t really think about data validation when a project is small.\n\nYou throw a couple of `z.object({ ... })` schemas into a file, call `parse`, and move on with your life.\n\nThen the app grows.\n\nYou add microservices. Frontend + backend share contracts. APIs move fast. Suddenly your “nice little schema library” is sitting in:\n\n- Gateway validation\n- Queue consumers\n- Edge functions\n- React forms\n- Test fixtures\n\n…and every tiny performance or DX quirk starts to matter.\n\nAt that point, the question quietly changes from “Which validator is cool?” to:\n\n> _“Which validator will still be a good idea 18 months from now?”_\n\nLet’s walk through **zod**, **valibot**, and **superstruct** with that in mind: TypeScript data validators at _scale_, not just in a tutorial.\n\n## The Shared Goal: Runtime Contracts for Your TypeScript Types\n\nTypeScript’s type system is compile-time only. Your API consumers, browser payloads, and queue messages do not care what `tsc` believes.\n\n## Get Codastra’s stories in your inbox\n\nJoin Medium for free to get updates from this writer.\n\nSubscribe\n\nSubscribe\n\nRemember me for faster sign in\n\nAll three libraries basically try to give you the same superpower:\n\n```\n// 1) Define a runtime schema\n// 2) Get a TypeScript type from it\n// 3) Validate untrusted data at the boundaries\n```\n\nIn slightly different accents, they all implement “schema as code”:\n\n- Describe shapes and constraints.\n- Validate runtime data.\n- Surface typed, structured errors.\n\nThe differences matter in ergonomics, performance, and how well they slot into a big codebase.\n\n## Quick Taste: What the APIs Feel Like\n\nLet’s use a simple `User` shape across all three:\n\n## zod\n\n```\nimport { z } from 'zod';\n\nconst User = z.object({\n id: z.string().uuid(),\n email: z.string().email(),\n role: z.enum(['user', 'admin']),\n createdAt: z.coerce.date(),\n});\n\ntype User = z.infer;\n\nconst user = User.parse(input); // throws on error\n```\n\n**Vibe:** expressive, batteries-included, very readable. Zod feels like a tiny DSL that lives comfortably in TypeScript.\n\n## valibot\n\n```\nimport {\n object,\n string,\n literal,\n union,\n transform,\n email,\n uuid,\n} from 'valibot';\n\nconst User = object({\n id: string([uuid()]),\n email: string([email()]),\n role: union([literal('user'), literal('admin')]),\n createdAt: transform(string(), (s) => new Date(s)),\n});\n\ntype User = typeof User['output'];\n\nconst result = User.parse(input); // throws by default, other APIs available\n```\n\n**Vibe:** schema + pipelines. The API leans into composition and small helpers, with an eye on performance and bundle size.\n\n## superstruct\n\n```\nimport { object, string, literal, union, date, assert } from 'superstruct';\n\nconst Role = union([literal('user'), literal('admin')]);\n\nconst User = object({\n id: string(),\n email: string(),\n role: Role,\n createdAt: date(),\n});\n\ntype User = typeof User; // just the shape, not inferred as strongly\n\nassert(input, User); // throws if invalid\n```\n\n**Vibe:** minimal, unopinionated, a bit more “JS-first with TS support” than “TS-native”.\n\n## Architecture: Where Validators Sit in a Real System\n\nIn a serious TypeScript deployment, validators end up at every boundary:\n\n```\n +---------------------------+\nBrowser / FE | React / Next.js |\n | - form validation (zod?) |\n +-------------+-------------+\n |\n v\n +---------------------------+\nAPI Gateway | Node / Edge / Server |\n | - request validation |\n | - response shaping |\n +-------------+-------------+\n |\n v\n +---------------------------+\nServices | Workers / Functions |\n | - queue / event schemas |\n | - external API payloads |\n +---------------------------+\n |\n v\n +---------------------------+\nStorage | DB / KV / Cache |\n | - config shapes |\n +---------------------------+\n```\n\nAt scale, you want:\n\n- **One schema per contract**, reused across these layers.\n- A library that doesn’t kill bundle size on the client.\n- Good error messages for both logs and UX.\n- A migration story if you ever need to swap libraries.\n\nLet’s see how each scores.\n\n## zod: The Default Choice (For a Reason)\n\nIf you look around large TS codebases, zod is everywhere.\n\n## Why people love it\n\n- **Fantastic DX.** The API reads like declarative TypeScript. `z.enum`, `z.union`, `z.discriminatedUnion`, `z.coerce`, `z.record` — it all feels natural.\n- **Type inference is top tier.** You get precise types, even for gnarly unions and transforms.\n- **Rich ecosystem.** tRPC, Drizzle, Next.js, Remix, and others often have first-class zod support or examples.\n- **Great for shared contracts.** Create a `schema/user.ts` and use it in React, Node, tests, and stories.\n\n## Where it hurts at scale\n\n- **Bundle size.** Zod is relatively heavy. For a monorepo that ships to multiple frontends, that can add up.\n- **Performance under heavy load.** For average workloads it’s fine, but if you’re validating tens of thousands of records per second in a Node service, zod can become a noticeable CPU line item.\n- **Overuse for “simple” checks.** Teams sometimes drag zod into places where a typed helper or a few `typeof` checks would be enough.\n\n**Rough verdict:** If DX and ecosystem matter more than micro-optimizations, zod is still the “default yes” for many teams.\n\n## valibot: “Like zod, but fast”\n\nvalibot showed up later with a pretty clear thesis: **runtime validation with better performance and smaller bundles.**\n\n## What it brings to the table\n\n- **Performance-focused architecture.** Internals are optimized to minimize allocations and overhead.\n- **Composable constraints.** Validators are tiny functions you attach to fields, which scales nicely for complex rules.\n- **Lean bundle footprint.** Important when you have multiple microfrontends or embed validators in edge handlers.\n- **Typed input / output separation.** You can reason about what kind of value goes in and what comes out after transforms.\n\n## When valibot makes sense\n\n- You have **zod-like use cases** but are hitting performance or bundle ceiling.\n- You’re building **edge runtimes** (Cloudflare Workers, Vercel Edge) where cold starts & CPU are precious.\n- You want a library designed with **modern TS and bundlers** in mind from day one.\n\nTrade-off: the ecosystem is younger. You may not find as many off-the-shelf integrations, so expect to write a bit more glue code.\n\n## superstruct: The Minimalist Veteran\n\nsuperstruct has been around for a while. It’s small, flexible, and more “JavaScript library with TypeScript support” than TS-first.\n\n## Where it shines\n\n- **Simplicity.** The mental model is approachable: struct + assert.\n- **Tiny surface area.** Easier to grok for teams that don’t want a DSL feel.\n- **Good fit for libraries.** If you’re building a generic JS/TS library and don’t want to pull in zod, superstruct can be a lighter option.\n\n## Where it shows its age\n\n- Type inference isn’t as rich as zod/valibot. You may need more manual typing.\n- Fewer high-level helpers for things like discriminated unions or advanced refinements.\n- Slightly less ergonomic in large, type-driven codebases.\n\nI tend to think of superstruct as: **great for small, focused validation inside a library or tool**, but not always the strongest choice as the _primary_ contract system across a big TS monorepo.\n\n## Performance, Error Handling, and Team Scale\n\nWhen you zoom out to “we have a lot of services and people,” three things really matter.\n\n## 1\\. Performance\n\n- **Node-heavy, high-throughput pipelines?** valibot often wins.\n- **Moderate traffic, human-facing apps?** zod is usually fast enough.\n- **Library dev targeting broad JS audience?** superstruct is fine and minimal.\n\nIf you suspect validation is hot-path, write a tiny benchmark that mirrors your real payloads. Numbers beat vibes.\n\n## 2\\. Error Handling\n\nGood error messages are not just for users; they’re for logs, alerts, and dashboards.\n\n- zod: rich error trees, great for mapping into UI error messages and structured logs.\n- valibot: also surfaces structured, navigable errors with a focus on clarity.\n- superstruct: more minimal; you may need to layer your own error formatting.\n\nFor big teams, the ability to **standardize error shapes** (e.g., `code`, `path`, `message`) matters a lot. zod and valibot both support that pattern well.\n\n## 3\\. Team Ergonomics\n\nThis is the underrated part.\n\n- If your team lives in TypeScript and loves “types as the source of truth,” zod’s **DX and community examples** reduce friction.\n- If you have multiple teams building microfrontends and edge handlers, valibot’s **performance + bundle story** can keep things sustainable.\n- If you just need lightweight validation inside a library with minimal opinions, superstruct is **easy to embed**.\n\nThe “best” validator is the one your team will _actually use consistently_ at boundaries.\n\n## So… Which One Should You Pick?\n\nLet’s be blunt:\n\n- **zod** — pick this if you want the mainstream, high-DX, ecosystem-friendly option and you’re not currently bottlenecked on validation performance.\n- **valibot** — pick this if you want zod-like expressiveness but expect to care a lot about **throughput and bundle size** over the next year.\n- **superstruct** — pick this if you’re building **reusable JS/TS libraries** and want lightweight, no-fuss validation that doesn’t dominate your dependency graph.\n\nYou can also mix and migrate:\n\n- Start with zod, migrate hot paths to valibot if needed.\n- Use superstruct inside SDKs but zod/valibot at your application edges.\n\nNothing says you must marry a single library forever.\n\n## Wrap-Up: Validators as Infrastructure, Not Utilities\n\nData validators in TypeScript aren’t just utilities. In a large system, they become:\n\n- Your **API contract language**\n- Your **defense line** against corrupted events\n- Your **source of truth** for what’s actually allowed to flow through\n\nThat decision deserves more thought than “I saw it in a tutorial once.”\n\nIf you’re mid-journey, here’s a practical next step:\n\n> _Pick one core schema (like_`User` _or_`Order` _), implement it in zod, valibot, and superstruct, then run a small benchmark and DX comparison with your team._\n\nSee which one _feels_ right and which one your future self is least likely to curse.\n\nAnd when you’ve done that experiment, drop a comment with what you chose and why. Those war stories are way more useful than any benchmark screenshot.\n\n[Typescript](https://medium.com/tag/typescript?source=post_page-----177581543ac5---------------------------------------)\n\n[Zod](https://medium.com/tag/zod?source=post_page-----177581543ac5---------------------------------------)\n\n[AI](https://medium.com/tag/ai?source=post_page-----177581543ac5---------------------------------------)\n\n[Superstructure](https://medium.com/tag/superstructure?source=post_page-----177581543ac5---------------------------------------)\n\n[Data Validation](https://medium.com/tag/data-validation?source=post_page-----177581543ac5---------------------------------------)\n\n[![Codastra](https://miro.medium.com/v2/resize:fill:48:48/1*IZcptplBcXPdWGYUkOqYnA.png)](https://medium.com/@2nick2patel2?source=post_page---post_author_info--177581543ac5---------------------------------------)\n\n[![Codastra](https://miro.medium.com/v2/resize:fill:64:64/1*IZcptplBcXPdWGYUkOqYnA.png)](https://medium.com/@2nick2patel2?source=post_page---post_author_info--177581543ac5---------------------------------------)\n\nFollow\n\n[**Written by Codastra**](https://medium.com/@2nick2patel2?source=post_page---post_author_info--177581543ac5---------------------------------------)\n\n[908 followers](https://medium.com/@2nick2patel2/followers?source=post_page---post_author_info--177581543ac5---------------------------------------)\n\n· [662 following](https://medium.com/@2nick2patel2/following?source=post_page---post_author_info--177581543ac5---------------------------------------)\n\nExploring where code meets creativity. Writing on AI, tech, and the craft of building systems with rhythm, clarity, and orchestration.\n\nFollow\n\n## No responses yet\n\n![](https://miro.medium.com/v2/resize:fill:32:32/1*dmbNkD5D-u45r44go_cf0g.png)\n\nWrite a response\n\n[What are your thoughts?](https://medium.com/m/signin?operation=register&redirect=https%3A%2F%2Fmedium.com%2F%402nick2patel2%2Ftypescript-data-validators-at-scale-zod-valibot-superstruct-compared-177581543ac5&source=---post_responses--177581543ac5---------------------respond_sidebar------------------)\n\nCancel\n\nRespond\n\n## More from Codastra\n\n![FastAPI + OpenTelemetry: Trace Every Request from Ingress to DB](https://miro.medium.com/v2/resize:fit:679/format:webp/1*4s_QAUzXMbiqK_v4a1k3GQ.png)\n\n[![Codastra](https://miro.medium.com/v2/resize:fill:20:20/1*IZcptplBcXPdWGYUkOqYnA.png)](https://medium.com/@2nick2patel2?source=post_page---author_recirc--177581543ac5----0---------------------90caeec9_3f2f_4859_977f_05dbcfae9246--------------)\n\n[Codastra](https://medium.com/@2nick2patel2?source=post_page---author_recirc--177581543ac5----0---------------------90caeec9_3f2f_4859_977f_05dbcfae9246--------------)\n\nNov 29, 2025\n\n[A clap icon29](https://medium.com/@2nick2patel2/fastapi-opentelemetry-trace-every-request-from-ingress-to-db-8108866dba78?source=post_page---author_recirc--177581543ac5----0---------------------90caeec9_3f2f_4859_977f_05dbcfae9246--------------)\n\n![DuckDB Geospatial: Vector Tiles, Rasters, and Fast Maps on Parquet](https://miro.medium.com/v2/resize:fit:679/format:webp/1*m0jZ14Le0Vf5b9LV11JMbg.png)\n\n[![Codastra](https://miro.medium.com/v2/resize:fill:20:20/1*IZcptplBcXPdWGYUkOqYnA.png)](https://medium.com/@2nick2patel2?source=post_page---author_recirc--177581543ac5----1---------------------90caeec9_3f2f_4859_977f_05dbcfae9246--------------)\n\n[Codastra](https://medium.com/@2nick2patel2?source=post_page---author_recirc--177581543ac5----1---------------------90caeec9_3f2f_4859_977f_05dbcfae9246--------------)\n\nNov 28, 2025\n\n[A clap icon57](https://medium.com/@2nick2patel2/duckdb-geospatial-vector-tiles-rasters-and-fast-maps-on-parquet-f08ae70c73b8?source=post_page---author_recirc--177581543ac5----1---------------------90caeec9_3f2f_4859_977f_05dbcfae9246--------------)\n\n![We Benchmarked Pandas vs Polars vs DuckDB: Jaw-Dropping Results](https://miro.medium.com/v2/resize:fit:679/format:webp/1*gnGAJzEW6HLC7tOvhZLR6w.png)\n\n[![Codastra](https://miro.medium.com/v2/resize:fill:20:20/1*IZcptplBcXPdWGYUkOqYnA.png)](https://medium.com/@2nick2patel2?source=post_page---author_recirc--177581543ac5----2---------------------90caeec9_3f2f_4859_977f_05dbcfae9246--------------)\n\n[Codastra](https://medium.com/@2nick2patel2?source=post_page---author_recirc--177581543ac5----2---------------------90caeec9_3f2f_4859_977f_05dbcfae9246--------------)\n\nNov 4, 2025\n\n[A clap icon76\\\\\n\\\\\nA response icon2](https://medium.com/@2nick2patel2/we-benchmarked-pandas-vs-polars-vs-duckdb-jaw-dropping-results-29fb05809424?source=post_page---author_recirc--177581543ac5----2---------------------90caeec9_3f2f_4859_977f_05dbcfae9246--------------)\n\n![Python Build Speed: uv Pipelines and Wheels](https://miro.medium.com/v2/resize:fit:679/format:webp/1*VExC-Hvk1b1qIYKGczLZcg.png)\n\n[![Codastra](https://miro.medium.com/v2/resize:fill:20:20/1*IZcptplBcXPdWGYUkOqYnA.png)](https://medium.com/@2nick2patel2?source=post_page---author_recirc--177581543ac5----3---------------------90caeec9_3f2f_4859_977f_05dbcfae9246--------------)\n\n[Codastra](https://medium.com/@2nick2patel2?source=post_page---author_recirc--177581543ac5----3---------------------90caeec9_3f2f_4859_977f_05dbcfae9246--------------)\n\nNov 16, 2025\n\n[A clap icon45](https://medium.com/@2nick2patel2/python-build-speed-uv-pipelines-and-wheels-871b742662e8?source=post_page---author_recirc--177581543ac5----3---------------------90caeec9_3f2f_4859_977f_05dbcfae9246--------------)\n\n[See all from Codastra](https://medium.com/@2nick2patel2?source=post_page---author_recirc--177581543ac5---------------------------------------)\n\n## Recommended from Medium\n\n![Junior Devs Use try-catch Everywhere. Senior Devs Use These 4 Exception Handling Patterns](https://miro.medium.com/v2/resize:fit:679/format:webp/1*7seiGDAW_yeQLR__Yt3vPA.png)\n\n[![Stackademic](https://miro.medium.com/v2/resize:fill:20:20/1*U-kjsW7IZUobnoy1gAp1UQ.png)](https://medium.com/stackademic?source=post_page---read_next_recirc--177581543ac5----0---------------------8df54352_d784_42c0_8aa5_3e0a8d8a8f6d--------------)\n\nIn\n\n[Stackademic](https://medium.com/stackademic?source=post_page---read_next_recirc--177581543ac5----0---------------------8df54352_d784_42c0_8aa5_3e0a8d8a8f6d--------------)\n\nby\n\n[HabibWahid](https://medium.com/@habib11wahid?source=post_page---read_next_recirc--177581543ac5----0---------------------8df54352_d784_42c0_8aa5_3e0a8d8a8f6d--------------)\n\nFeb 1\n\n[A clap icon1.91K\\\\\n\\\\\nA response icon37](https://medium.com/stackademic/junior-devs-use-try-catch-everywhere-senior-devs-use-these-4-exception-handling-patterns-dcd869ed6551?source=post_page---read_next_recirc--177581543ac5----0---------------------8df54352_d784_42c0_8aa5_3e0a8d8a8f6d--------------)\n\n![Why Vue.js Might Be the Best Frontend Framework You’re Not Using (Yet) 🚀](https://miro.medium.com/v2/resize:fit:679/format:webp/0*rKQmjhqwxHGIQk3I)\n\n[![Priyanshu Rajput](https://miro.medium.com/v2/resize:fill:20:20/1*sxGotnvHnjsRZTALIso76w.jpeg)](https://medium.com/@priyansu011?source=post_page---read_next_recirc--177581543ac5----1---------------------8df54352_d784_42c0_8aa5_3e0a8d8a8f6d--------------)\n\n[Priyanshu Rajput](https://medium.com/@priyansu011?source=post_page---read_next_recirc--177581543ac5----1---------------------8df54352_d784_42c0_8aa5_3e0a8d8a8f6d--------------)\n\nMar 8\n\n[A clap icon1](https://medium.com/@priyansu011/why-vue-js-might-be-the-best-frontend-framework-youre-not-using-yet-7e1ce0798c1b?source=post_page---read_next_recirc--177581543ac5----1---------------------8df54352_d784_42c0_8aa5_3e0a8d8a8f6d--------------)\n\n![🚀 Functional Error Handling in TypeScript with the Result Pattern](https://miro.medium.com/v2/resize:fit:679/format:webp/0*AmnVM5Qnu7AuAHxB)\n\n[![Arg Software](https://miro.medium.com/v2/resize:fill:20:20/1*Zi76SjvJYGFacYVHrZfAzw.jpeg)](https://medium.com/@arg-software?source=post_page---read_next_recirc--177581543ac5----0---------------------8df54352_d784_42c0_8aa5_3e0a8d8a8f6d--------------)\n\n[Arg Software](https://medium.com/@arg-software?source=post_page---read_next_recirc--177581543ac5----0---------------------8df54352_d784_42c0_8aa5_3e0a8d8a8f6d--------------)\n\nSep 26, 2025\n\n[A clap icon123\\\\\n\\\\\nA response icon6](https://medium.com/@arg-software/functional-error-handling-in-typescript-with-the-result-pattern-5b96a5abb6d3?source=post_page---read_next_recirc--177581543ac5----0---------------------8df54352_d784_42c0_8aa5_3e0a8d8a8f6d--------------)\n\n![Hexagonal Architecture in NestJS: Stop Mocking Prisma and Start Designing for Change](https://miro.medium.com/v2/resize:fit:679/format:webp/1*TT6ncOOnstH9Jsr7QEnpEQ.png)\n\n[![Sandy Zhang](https://miro.medium.com/v2/resize:fill:20:20/1*uBDb0zLTl8ld1MnpjPxIUA.jpeg)](https://medium.com/@srachel27?source=post_page---read_next_recirc--177581543ac5----1---------------------8df54352_d784_42c0_8aa5_3e0a8d8a8f6d--------------)\n\n[Sandy Zhang](https://medium.com/@srachel27?source=post_page---read_next_recirc--177581543ac5----1---------------------8df54352_d784_42c0_8aa5_3e0a8d8a8f6d--------------)\n\nMar 17\n\n[A clap icon1](https://medium.com/@srachel27/hexagonal-architecture-in-nestjs-stop-mocking-prisma-and-start-designing-for-change-6d1bab989622?source=post_page---read_next_recirc--177581543ac5----1---------------------8df54352_d784_42c0_8aa5_3e0a8d8a8f6d--------------)\n\n![Stop Writing Validation Code. Start Using Zod.](https://miro.medium.com/v2/resize:fit:679/format:webp/0*_mvMuSP0FyZMQ9ak.png)\n\n[![˗ˏˋ Ananya Hegde´ˎ˗](https://miro.medium.com/v2/resize:fill:20:20/1*KAqgcvQdal70tRscPwU8fA.gif)](https://medium.com/@ananyavhegde2001?source=post_page---read_next_recirc--177581543ac5----2---------------------8df54352_d784_42c0_8aa5_3e0a8d8a8f6d--------------)\n\n[˗ˏˋ Ananya Hegde´ˎ˗](https://medium.com/@ananyavhegde2001?source=post_page---read_next_recirc--177581543ac5----2---------------------8df54352_d784_42c0_8aa5_3e0a8d8a8f6d--------------)\n\nDec 7, 2025\n\n[A clap icon1](https://medium.com/@ananyavhegde2001/stop-writing-validation-code-start-using-zod-b0c361da62db?source=post_page---read_next_recirc--177581543ac5----2---------------------8df54352_d784_42c0_8aa5_3e0a8d8a8f6d--------------)\n\n![Prisma ORM 7.0 — Move Fast, Ship Safe: A Practical Guide for Production-Ready Applications](https://miro.medium.com/v2/resize:fit:679/format:webp/1*S3azSC7iyPj4Hm_EeLjemw.png)\n\n[![Prateek Kumar](https://miro.medium.com/v2/resize:fill:20:20/0*51X9e8YUKQY5IznM.)](https://medium.com/@prateek.dbg?source=post_page---read_next_recirc--177581543ac5----3---------------------8df54352_d784_42c0_8aa5_3e0a8d8a8f6d--------------)\n\n[Prateek Kumar](https://medium.com/@prateek.dbg?source=post_page---read_next_recirc--177581543ac5----3---------------------8df54352_d784_42c0_8aa5_3e0a8d8a8f6d--------------)\n\nNov 22, 2025\n\n[See more recommendations](https://medium.com/?source=post_page---read_next_recirc--177581543ac5---------------------------------------)\n\n[Help](https://help.medium.com/hc/en-us?source=post_page-----177581543ac5---------------------------------------)\n\n[Status](https://status.medium.com/?source=post_page-----177581543ac5---------------------------------------)\n\n[About](https://medium.com/about?autoplay=1&source=post_page-----177581543ac5---------------------------------------)\n\n[Careers](https://medium.com/jobs-at-medium/work-at-medium-959d1a85284e?source=post_page-----177581543ac5---------------------------------------)\n\n[Press](mailto:pressinquiries@medium.com)\n\n[Blog](https://blog.medium.com/?source=post_page-----177581543ac5---------------------------------------)\n\n[Privacy](https://policy.medium.com/medium-privacy-policy-f03bf92035c9?source=post_page-----177581543ac5---------------------------------------)\n\n[Rules](https://policy.medium.com/medium-rules-30e5502c4eb4?source=post_page-----177581543ac5---------------------------------------)\n\n[Terms](https://policy.medium.com/medium-terms-of-service-9db0094a1e0f?source=post_page-----177581543ac5---------------------------------------)\n\n[Text to speech](https://speechify.com/medium?source=post_page-----177581543ac5---------------------------------------)\n\nreCAPTCHA\n\nRecaptcha requires verification.\n\n[Privacy](https://www.google.com/intl/en/policies/privacy/) \\- [Terms](https://www.google.com/intl/en/policies/terms/)\n\nprotected by **reCAPTCHA**\n\n[Privacy](https://www.google.com/intl/en/policies/privacy/) \\- [Terms](https://www.google.com/intl/en/policies/terms/)","metadata":{"al:ios:app_store_id":"828256236","title":"TypeScript Data Validators at Scale: zod, valibot, superstruct Compared | by Codastra | Medium","twitter:app:id:iphone":"828256236","theme-color":"#000000","og:type":"article","ogDescription":"Choosing the right runtime validator when your TypeScript codebase stops being “just a project” and becomes infrastructure.","ogUrl":"https://medium.com/@2nick2patel2/typescript-data-validators-at-scale-zod-valibot-superstruct-compared-177581543ac5","ogSiteName":"Medium","fb:app_id":"542599432471018","apple-itunes-app":"app-id=828256236, app-argument=/@2nick2patel2/typescript-data-validators-at-scale-zod-valibot-superstruct-compared-177581543ac5, affiliate-data=pt=698524&ct=smart_app_banner&mt=8","og:description":"Choosing the right runtime validator when your TypeScript codebase stops being “just a project” and becomes infrastructure.","og:image":"https://miro.medium.com/v2/resize:fit:1200/1*F2GvuH0OyiTeZTN0wtdxkg.png","twitter:app:url:iphone":"medium://p/177581543ac5","ogImage":"https://miro.medium.com/v2/resize:fit:1200/1*F2GvuH0OyiTeZTN0wtdxkg.png","ogTitle":"TypeScript Data Validators at Scale: zod, valibot, superstruct Compared","al:ios:app_name":"Medium","al:web:url":"https://medium.com/@2nick2patel2/typescript-data-validators-at-scale-zod-valibot-superstruct-compared-177581543ac5","twitter:site":"@Medium","robots":"index,noarchive,follow,max-image-preview:large","al:ios:url":"medium://p/177581543ac5","author":"Codastra","referrer":"unsafe-url","viewport":"width=device-width,minimum-scale=1,initial-scale=1,maximum-scale=1","al:android:package":"com.medium.reader","article:author":"https://medium.com/@2nick2patel2","twitter:title":"TypeScript Data Validators at Scale: zod, valibot, superstruct Compared","og:site_name":"Medium","publishedTime":"2025-12-06T01:32:10.975Z","language":"en","twitter:app:name:iphone":"Medium","article:published_time":"2025-12-06T01:32:10.975Z","twitter:image:src":"https://miro.medium.com/v2/resize:fit:1200/1*F2GvuH0OyiTeZTN0wtdxkg.png","twitter:data1":"7 min read","og:title":"TypeScript Data Validators at Scale: zod, valibot, superstruct Compared","al:android:app_name":"Medium","twitter:description":"Choosing the right runtime validator when your TypeScript codebase stops being “just a project” and becomes infrastructure.","description":"TypeScript Data Validators at Scale: zod, valibot, superstruct Compared Choosing the right runtime validator when your TypeScript codebase stops being “just a project” and becomes …","og:url":"https://medium.com/@2nick2patel2/typescript-data-validators-at-scale-zod-valibot-superstruct-compared-177581543ac5","twitter:label1":"Reading time","twitter:card":"summary_large_image","al:android:url":"medium://p/177581543ac5","favicon":"https://miro.medium.com/v2/5d8de952517e8160e40ef9841c781cdc14a5db313057fa3c3de41c6f5b494b19","scrapeId":"019d3953-9958-74c3-8f4c-cc0cf37af6c1","sourceURL":"https://medium.com/@2nick2patel2/typescript-data-validators-at-scale-zod-valibot-superstruct-compared-177581543ac5","url":"https://medium.com/@2nick2patel2/typescript-data-validators-at-scale-zod-valibot-superstruct-compared-177581543ac5","statusCode":200,"contentType":"text/html; charset=utf-8","timezone":"America/New_York","proxyUsed":"basic","cacheState":"miss","indexId":"9e7a9599-4ef2-49dc-b9b2-748a1b54701a","creditsUsed":1}},{"url":"https://devmystify.com/blog/top-6-validation-libraries-for-javascript-in-2025","title":"Top 6 Validation libraries for JavaScript in 2025 - Devmystify","description":"Superstruct takes a slightly different approach with a lightweight, functional style. Inspired by TypeScript, Flow, and GraphQL, its minimal ...","position":2,"markdown":"[← Back to Blog](https://devmystify.com/blog)\n\nTutorial9/24/2025Author: Tibo\n\n# Top 6 Validation libraries for JavaScript in 2025\n\njavascript\n\nValidating input is one of the most important parts of building robust applications. Whether you're working on frontend forms, backend APIs, or full-stack projects, reliable validation ensures that your inputs are clean, consistent, and secure.\n\nThe JavaScript ecosystem today offers many powerful libraries that make validation easier and more expressive. In this tutorial, we'll explore the top 6 validation libraries for JavaScript in 2025 and what makes each one stand out.\n\n> Note: The libraries in this tutorial aren’t ranked. We prefer to let you decide which one you prefer by providing a good overview for each one. Also, keep in mind that if the bundle size isn’t listed in the official docs, I’ll use\n> [Bundlephobia](https://bundlephobia.com/)\n> as a reference. In that case, the reported size may be larger, since it doesn’t account for tree-shaking optimizations.\n\n* * *\n\nBefore we get started, here is a quick overview of the 6 libraries we’ll cover in this tutorial:\n\n| Library | First Release | Standout Feature | Bundle Size |\n| --- | --- | --- | --- |\n| **Zod** | 2020 | Built for TypeScript; infers types directly from schemas for runtime + static safety | [265.6 kB (minified), 52.3 kB (gzipped)](https://bundlephobia.com/package/zod@4.1.11) |\n| **Yup** | 2017 | Declarative, chainable API; great with React and widely used in form libraries like Formik | [167.8 kB (minified), 52.6 kB (gzipped)](https://bundlephobia.com/package/joi@18.0.1) |\n| **Joi** | 2012 | Battle-tested; pioneered schema-as-object validation, core to Hapi.js ecosystem | [167.8 kB (minified), 52.6 kB (gzipped)](https://bundlephobia.com/package/joi@18.0.1) |\n| **Superstruct** | 2018 | Minimal, functional API inspired by TypeScript/GraphQL; lightweight and composable | [\\*\\*11.7\\*\\* kB (minified), 3.4 kB (gzipped)](https://bundlephobia.com/package/superstruct@2.0.2) |\n| **Vest** | 2020 | “Validation as tests”; TDD-style assertions make validation read like unit tests | [\\*\\*35.5\\*\\* kB (minified), 11.6 kB (gzipped)](https://bundlephobia.com/package/vest@5.4.6) |\n| **Valibot** | 2023 | Ultra-lightweight; functional `pipe` \\+ `check` API with strong TypeScript support | [1.37 kB](https://valibot.dev/guides/comparison/) |\n\nNow let’s dig in!\n\n* * *\n\n## Use Case Setup\n\nFirst, we’re going to set up a simple project in which we’ll integrate each library. This way, you can follow along (if you want to) and see how each library can be integrated in real code. We believe that this will allow you to quickly see which library syntax feels more natural for you.\n\nWe’ll be using **Express** for simplicity, and **TypeScript** to catch mistakes before they hit runtime:\n\n```bash\nmkdir top-6-validation && cd top-6-validation\nnpm init -y\n\n# core server deps\nnpm i express\nnpm i -D typescript ts-node-dev @types/express\n\n# validation libs (install now or as you go)\nnpm i zod yup joi superstruct vest valibot\n\n# (optional) Node types\nnpm i -D @types/node\n```\n\n`tsconfig.json`\n\n```json\n{\n \"compilerOptions\": {\n \"target\": \"ES2020\",\n \"module\": \"CommonJS\",\n \"strict\": true,\n \"esModuleInterop\": true,\n \"skipLibCheck\": true,\n \"outDir\": \"dist\"\n },\n \"include\": [\"src\"]\n}\n```\n\nAdd a dev script in `package.json`:\n\n```json\n{\n \"scripts\": {\n \"dev\": \"ts-node-dev --respawn --transpile-only src/server.ts\"\n }\n}\n```\n\n### Define a global type\n\n`src/types.ts`\n\n```tsx\nimport { Request } from 'express';\n\nexport type Party = {\n name: string;\n email: string;\n dob: string;\n};\n\nexport interface ValidatedRequest extends Request {\n validatedData?: any;\n}\n\nexport type ValidatorFunction = (body: unknown) => {\n ok: boolean;\n errors?: any;\n data?: any\n};\n```\n\n### Add a helper function\n\nThis function ensures all participants are adults (and shows how validators can handle custom logic).\n\n`src/utils.ts`\n\n```tsx\nexport function isAdult(dob: string) {\n const d = new Date(dob);\n if (Number.isNaN(d.getTime())) return false;\n\n const today = new Date();\n const age = today.getFullYear() - d.getFullYear();\n const hasBirthdayPassed =\n today.getMonth() > d.getMonth() ||\n (today.getMonth() === d.getMonth() && today.getDate() >= d.getDate());\n const realAge = hasBirthdayPassed ? age : age - 1;\n\n return realAge >= 18;\n}\n```\n\n### Baseline Express app\n\n`src/server.ts`\n\n```tsx\nimport express from 'express';\nimport type { NextFunction, Response } from 'express';\nimport { ValidatedRequest, ValidatorFunction } from './types';\n\nconst app = express();\napp.use(express.json());\n\n// we will change this value to test different validators\nconst LIB: 'zod' | 'yup' | 'joi' | 'superstruct' | 'vest' | 'valibot' = 'zod';\n\nimport {validateParty as zodValidateParty} from './validators/zod';\n// import {validateParty as yupValidateParty} from './validators/yup';\n// import {validateParty as joiValidateParty} from './validators/joi';\n// import {validateParty as superstructValidateParty} from './validators/superstruct';\n// import {validateParty as vestValidateParty} from './validators/vest';\n// import {validateParty as valibotValidateParty} from './validators/valibot';\n\nfunction pickValidator(): ValidatorFunction {\n switch (LIB) {\n case 'zod': return zodValidateParty;\n // case 'yup': return yupValidateParty;\n // case 'joi': return joiValidateParty;\n // case 'superstruct': return superstructValidateParty;\n // case 'vest': return vestValidateParty;\n // case 'valibot': return valibotValidateParty;\n }\n}\n\nfunction validateBody(validator: ValidatorFunction) {\n return (req: ValidatedRequest, res: Response, next: NextFunction) => {\n const result = validator(req.body);\n if (!result.ok) {\n return res.status(400).json({ errors: result.errors });\n }\n req.validatedData = result.data;\n next();\n };\n}\n\napp.post('/api/parties', validateBody(pickValidator()), (req: ValidatedRequest, res: Response) => {\n return res.status(200).json({ message: 'OK', data: req.validatedData });\n})\n\napp.listen(3000, () => {\n console.log('Server on http://localhost:3000 (library =', LIB, ')');\n});\n```\n\nAt this point, you’ll probably see some red squiggly lines, but don’t worry, we’ll fix them right now by implementing our first validator.\n\n* * *\n\n## 1\\. Zod\n\n- Release year: 2021\n- Maintainer/Repo:\n[https://github.com/colinhacks](https://github.com/colinhacks)\n- Bundle size:\n[265.6 kB (minified), 52.3 kB (gzipped)](https://bundlephobia.com/package/zod@4.1.11)\n\n[Zod](https://zod.dev/)\nmight be the “new kid on the block”, but it has quickly gained massive popularity. If you work with TypeScript, you’ve probably already heard of it. Zod is built from the ground up for TypeScript. Instead of just validating, it infers TypeScript types directly from schemas, giving you both runtime and compile-time safety.\n\nFor each validator, we’ll define:\n\n- The validation schema: how we want our data to look like.\n- A validation function: how the validation schema is used to validate an input, and how validation errors should be handled.\n\nHere is our Zod validator, with comments explaining how each section works.\n\n`src/validators/zod.ts`\n\n```tsx\nimport { z } from \"zod\";\nimport type { Party } from \"../types\";\nimport { isAdult } from \"../utils\";\n\n// This is our zod schema for validation\nconst PartySchema = z.object({\n name: z.string().min(5, \"Name must be at least 5 characters long\"),\n email: z.email(\"Invalid email\"),\n dob: z\n .string()\n .refine((value) => !Number.isNaN(Date.parse(value)), \"Invalid date\")\n .refine(isAdult, 'Must be 18 or older'),\n});\n\n// This is our zod validator function\n// It takes a body of unknown type and returns a validation result\nexport function validateParty(\n body: unknown\n):\n | { ok: true; data: Party }\n | { ok: false; errors: Array<{ field?: string; message: string }> } {\n\n // this is where we validate the body using zod\n const parsed = PartySchema.safeParse(body);\n if (!parsed.success) {\n // if validation fails, we return the issues\n const issues = parsed.error.issues.map((i) => ({\n field: i.path.join(\".\"),\n message: i.message,\n }));\n return { ok: false, errors: issues };\n }\n\n // if validation passes, we return the data\n return { ok: true, data: parsed.data };\n}\n```\n\nSince Zod is our default validator, we don’t need to change `server.ts`. Let’s test it:\n\n```bash\n# ✅ valid\ncurl -s -X POST \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"name\":\"Alice\",\"email\":\"alice@example.com\",\"dob\":\"2000-05-20\"}' | jq .\n\n# ❌ invalid\ncurl -s -X POST \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"name\":\"A\",\"email\":\"not-an-email\",\"dob\":\"not-a-date\"}' | jq .\n```\n\nYou’ll see something like:\n\n```json\n{\n \"message\": \"OK\",\n \"data\": {\n \"name\": \"Alice\",\n \"email\": \"alice@example.com\",\n \"dob\": \"2000-05-20\"\n }\n}\n```\n\nOr, for invalid requests:\n\n```json\n{\n \"errors\": [\\\n {\\\n \"field\": \"name\",\\\n \"message\": \"Name must be at least 5 characters long\"\\\n },\\\n {\\\n \"field\": \"email\",\\\n \"message\": \"Invalid email\"\\\n },\\\n {\\\n \"field\": \"dob\",\\\n \"message\": \"Invalid date\"\\\n },\\\n {\\\n \"field\": \"dob\",\\\n \"message\": \"Must be 18 or older\"\\\n }\\\n ]\n}\n```\n\n> Note: I won’t show the `curl` commands and results for every library, as it’s too verbose. You can jot down the commands or use a client like HTTPie, Thunder Client, or Postman to fire off requests. The results will follow the same pattern for each validator.\n\n* * *\n\n## 2\\. Yup\n\n- Release year: 2015\n- Maintainer/Repo:\n[https://github.com/jquense](https://github.com/jquense)\n- Bundle size:\n[167.8 kB (minified), 52.6 kB (gzipped)](https://bundlephobia.com/package/joi@18.0.1)\n\n[Yup](https://github.com/jquense/yup?tab=readme-ov-file)\nis another schema-based validator and is extremely popular for frontend validation. Its declarative, chain-able API is inspired by\n[Joi](https://joi.dev/)\n, but comes with a friendlier syntax for React apps. Often the default in form libraries like\n[Formik](https://formik.org/)\n. Even though this tutorial is backend-focused, Yup still works just fine here.\n\n`src/validators/yup.ts`\n\n```tsx\nimport * as Yup from 'yup';\nimport type { Party } from \"../types\";\nimport { isAdult } from \"../utils\";\n\n// This is our yup schema for validation\nconst PartySchema = Yup.object({\n name: Yup.string().min(5, \"Name must be at least 5 characters long\").required(),\n email: Yup.string().email(\"Invalid email\").required(),\n dob: Yup.string()\n .test('valid-date', 'Invalid date', v => !!v && !Number.isNaN(Date.parse(v)))\n .test('adult', 'Must be 18 or older', v => !!v && isAdult(v))\n .required(),\n});\n\n// This is our yup validator function\n// It takes a body of unknown type and returns a validation result\nexport function validateParty(body: unknown) {\n try {\n // this is where we validate the body using yup\n const data = PartySchema.validateSync(body, { abortEarly: false });\n return { ok: true, data: data as Party };\n } catch (err: any) {\n // if validation fails, we return the issues\n const errors = (err.inner ?? []).map((e: any) => ({\n field: e.path,\n message: e.message,\n }));\n return { ok: false, errors };\n }\n}\n```\n\nNow update `server.ts` by uncommenting the import and switching the active validator:\n\n```tsx\n// change LIB to 'yup'\nconst LIB: 'zod' | 'yup' | 'joi' | 'superstruct' | 'vest' | 'valibot' = 'yup';\n\n// uncomment yup import statement\nimport {validateParty as zodValidateParty} from './validators/zod';\nimport {validateParty as yupValidateParty} from './validators/yup';\n// import {validateParty as joiValidateParty} from './validators/joi';\n// ... the rest of the validators\n\nfunction pickValidator() {\n switch (LIB) {\n case 'zod': return zodValidateParty;\n case 'yup': return yupValidateParty; // <- uncomment this line\n // case 'joi': return joiValidateParty;\n // case 'superstruct': return superstructValidateParty;\n // .. the rest of the validators\n }\n}\n```\n\nAnd then we can test our API again. Now that you know the flow, we’ll go through the remaining four libraries.\n\n* * *\n\n## 3\\. Joi\n\n- Release year: 2012\n- Maintainer/Repo:\n[https://github.com/hapijs/joi](https://github.com/hapijs/joi)\n- Bundle size:\n[167.8 kB (minified), 52.6 kB (gzipped)](https://bundlephobia.com/package/joi@18.0.1)\n\n[Joi](https://joi.dev/)\nhas been around for a long time and is one of the most widely used validation libraries in backend development. If you’re building APIs with Express, Hapi, or any Node.js framework, chances are you’ve seen Joi in action before. It has been battle-tested for years, especially in the Hapi.js ecosystem. It pioneered the “schema as object” approach many others followed.\n\n`src/validators/joi.ts`\n\n```tsx\nimport Joi from \"joi\";\nimport type { Party } from \"../types\";\nimport { isAdult } from \"../utils\";\n\n// This is our joi schema for validation\nconst PartySchema = Joi.object({\n name: Joi.string().min(5).required().messages({\n \"string.min\": \"Name must be at least 5 characters long\",\n \"string.empty\": \"Name is required\",\n \"any.required\": \"Name is required\",\n }),\n email: Joi.string().email().required().messages({\n \"string.email\": \"Invalid email\",\n \"string.empty\": \"Email is required\",\n \"any.required\": \"Email is required\",\n }),\n dob: Joi.string()\n .custom((v, helpers) => {\n if (Number.isNaN(Date.parse(v))) {\n return helpers.error(\"dob.invalidDate\"); // use a custom error code\n }\n if (!isAdult(v)) {\n return helpers.error(\"dob.notAdult\"); // use another custom error code\n }\n return v;\n })\n .required()\n .messages({\n \"dob.invalidDate\": \"Invalid date\", // map your custom code → message\n \"dob.notAdult\": \"Must be 18 or older\",\n \"any.required\": \"Date of birth is required\",\n }),\n});\n\n// This is our joi validator function\nexport function validateParty(body: unknown) {\n const { error, value } = PartySchema.validate(body, { abortEarly: false });\n\n if (error) {\n return {\n ok: false,\n errors: error.details.map((d) => ({\n field: d.path.join(\".\"),\n message: d.message,\n })),\n };\n }\n\n return { ok: true, data: value as Party };\n}\n```\n\n* * *\n\n## 4\\. Superstruct\n\n- Release year: 2017\n- Maintainer/Repo:\n[https://github.com/ianstormtaylor](https://github.com/ianstormtaylor)\n- Bundle size:\n[\\*\\*11.7\\*\\* kB (minified), 3.4 kB (gzipped)](https://bundlephobia.com/package/superstruct@2.0.2)\n\n[Superstruct](https://docs.superstructjs.org/guides/05-handling-errors)\ntakes a slightly different approach with a lightweight, functional style. Inspired by TypeScript, Flow, and GraphQL, its minimal API makes it easy to define small, composable structs. Perfect when you want validation without heavy dependencies.\n\n`src/validators/superstruct.ts`\n\n```tsx\nimport {\n object,\n string,\n refine,\n create,\n} from \"superstruct\";\nimport type { Party } from \"../types\";\nimport { isAdult } from \"../utils\";\n\nconst EmailRegex = /^\\\\S+@\\\\S+\\\\.\\\\S+$/;\n\nconst validateEmail = (value: string) => {\n return EmailRegex.test(value);\n};\n\nconst PartyStruct = object({\n name: refine(\n string(),\n \"Name must be at least 5 characters long\",\n (v) => v.length >= 5\n ),\n email: refine(string(), \"Invalid email\", (v) => validateEmail(v)),\n dob: refine(\n string(),\n \"Must be a valid date and 18+\",\n (v) => !Number.isNaN(Date.parse(v)) && isAdult(v)\n ),\n});\n\nexport function validateParty(body: unknown) {\n try {\n const data = create(body, PartyStruct) as Party;\n return { ok: true, data };\n } catch (err: any) {\n const failures = err?.failures?.() ?? [];\n return {\n ok: false,\n errors: failures.map((f: any) => {\n console.log(f);\n return {\n field: f.path.join(\".\"),\n message: f.refinement,\n };\n }),\n };\n }\n}\n```\n\n* * *\n\n## 5\\. Vest\n\n- Release year: 2019\n- Maintainer/Repo:\n[https://github.com/ealush](https://github.com/ealush)\n- Bundle size:\n[\\*\\*35.5\\*\\* kB (minified), 11.6 kB (gzipped)](https://bundlephobia.com/package/vest@5.4.6)\n\n[Vest](https://vestjs.dev/)\nis probably the most unique one on this list. Instead of looking like a schema definition, it feels like you’re writing unit tests. Its “validation as tests” approach, inspired by TDD, turns rules into assertions and makes validation fun for developers who enjoy test-driven workflows.\n\n`src/validators/vest.ts`\n\n```tsx\nimport vest, { test, enforce } from 'vest';\nimport type { Party } from '../types';\nimport { isAdult } from '../utils';\n\nconst isEmail = (s: string) => /^\\\\S+@\\\\S+\\\\.\\\\S+$/.test(s);\nconst isDate = (s: string) => !Number.isNaN(Date.parse(s));\n\n// This is our vest test suite for validation\nconst validateSuite = vest.create('party', (data: any) => {\n test('name', 'Name must be at least 5 characters long', () => {\n enforce(data.name).isNotEmpty();\n enforce(data.name.length).greaterThanOrEquals(5);\n });\n\n test('email', 'Invalid email', () => {\n enforce(isEmail(data.email)).isTruthy();\n });\n\n test('dob', 'Must be a valid date and 18+', () => {\n enforce(isDate(data.dob)).isTruthy();\n enforce(isAdult(data.dob)).isTruthy();\n });\n});\n\n// This is our vest validator function\n// It takes a body of unknown type and returns a validation result\nexport function validateParty(body: any) {\n // this is where we validate the body using vest\n const res = validateSuite(body);\n if (res.hasErrors()) {\n // if validation fails, we return the issues\n const errs = res.getErrors();\n const flat = Object.entries(errs).flatMap(([field, messages]) =>\n (messages as string[]).map(m => ({ field, message: m }))\n );\n return { ok: false, errors: flat };\n }\n // if validation passes, we return the data\n return { ok: true, data: body as Party };\n}\n```\n\n* * *\n\n## 6\\. Valibot\n\n- Release year: 2023\n- Maintainer/Repo:\n[https://github.com/fabian-hiller](https://github.com/fabian-hiller)\n- Bundle size:\n[1.37 kB](https://valibot.dev/guides/comparison/)\n\n[Valibot](https://valibot.dev/)\nis a modern schema-based library with a clean, chain-able API. It’s ultra-lightweight and optimized for performance. Its `pipe` and `check` functions encourage a functional, composable approach to validation.\n\n`src/validators/valibot.ts`\n\n```tsx\nimport * as v from 'valibot';\nimport type { Party } from '../types';\nimport { isAdult } from '../utils';\n\n// This is our valibot schema for validation\nconst PartySchema = v.object({\n name: v.pipe(v.string(), v.minLength(5, 'Name must be at least 5 characters long')),\n email: v.pipe(v.string(), v.email('Invalid email')),\n dob: v.pipe(\n v.string(),\n v.check((value) => !isNaN(Date.parse(value)), 'Invalid date'),\n v.check((value) => isAdult(value), 'Must be 18 or older')\n ),\n});\n\n// This is our valibot validator function\n// It takes a body of unknown type and returns a validation result\nexport function validateParty(body: unknown) {\n // this is where we validate the body using valibot\n const result = v.safeParse(PartySchema, body);\n if (!result.success) {\n // if validation fails, we return the issues\n return {\n ok: false,\n errors: result.issues.map(i => ({\n field: i.path?.map(p => p.key).join('.') || undefined,\n message: i.message,\n })),\n };\n }\n\n // if validation passes, we return the data\n return { ok: true, data: result.output as Party };\n}\n```\n\n* * *\n\n## Wrap-up\n\nWe covered a lot here, but this is really just the surface of what these libraries can do. The main goal was to give you a taste of their syntax and philosophy so you can choose the one that feels right for your next project.\n\nPersonally, I reach for **Zod** most often, but **Vest**’s test-like approach always feels like a fun change of pace.\n\nHow about you ? Do you already have a favorite, or will you try one of these in your next build? Let me know in the comments!\n\n![Tibo, creator of Devmystify](https://devmystify.com/_next/image?url=%2Fimages%2Ftibo.jpeg%3Fheight%3D320%26width%3D320&w=256&q=75)\n\n## Tibo\n\nHi, I'm the creator of Devmystify and author of Modular Rails and Master Ruby Web APIs.\n\nI built a 6-figure consulting business while living in Thailand and now share practical advice on freelancing and developer side hustles.\n\n[← Back to Blog](https://devmystify.com/blog)\n\n## Comments\n\nNo comments yet.\n\n## Level Up Your Dev Skills & Income 💰💻\n\nLearn how to **sharpen your programming skills, monetize your expertise, and build a future-proof career** — through freelancing, SaaS, digital products, or high-paying jobs.\n\nJoin 3,000+ Developers\n\nJoin 3,000+ developers learning how to **earn more, improve their skills, and future-proof their careers**.\n\nTop 6 Validation libraries for JavaScript in 2025 \\| Devmystify","metadata":{"ogSiteName":"Devmystify","baggage":"sentry-environment=production,sentry-release=b13526b174412118fb881e2c0aae83b283862817,sentry-public_key=1e58234f6b4617f2e003e9d3c26c73a4,sentry-trace_id=b287d3a35797d1ca7187a929aca2ff15,sentry-org_id=4510322862587904,sentry-transaction=GET%20%2Fblog%2F%5Bslug%5D,sentry-sampled=true,sentry-sample_rand=0.30809087491470866,sentry-sample_rate=1","og:title":"Top 6 Validation libraries for JavaScript in 2025 | Devmystify","title":"Top 6 Validation libraries for JavaScript in 2025 | Devmystify","og:url":"https://devmystify.com/blog/top-6-validation-libraries-for-javascript-in-2025","twitter:creator":"@Devmystify","sentry-trace":"b287d3a35797d1ca7187a929aca2ff15-1724b50b48cb2604-1","twitter:description":"Let’s take a look at the top 6 JS validation libraries in 2025, and get a quick overview of how to use them in your projects.","next-size-adjust":"","og:image:height":"630","description":"Let’s take a look at the top 6 JS validation libraries in 2025, and get a quick overview of how to use them in your projects.","og:type":"website","twitter:card":"summary_large_image","viewport":"width=device-width, initial-scale=1","og:locale":"en_US","og:site_name":"Devmystify","twitter:image":"https://d3tgxfx23qkrig.cloudfront.net/uploads/media/171/wide_thumb-top-6-validation-libraries-for-javascript-in-2025.png","language":"en","og:description":"Let’s take a look at the top 6 JS validation libraries in 2025, and get a quick overview of how to use them in your projects.","og:image:width":"1200","twitter:title":"Top 6 Validation libraries for JavaScript in 2025 | Devmystify","og:image":"https://d3tgxfx23qkrig.cloudfront.net/uploads/media/171/wide_thumb-top-6-validation-libraries-for-javascript-in-2025.png","favicon":"https://devmystify.com/favicon.ico","scrapeId":"019d3953-9958-74c3-8f4c-d063b129fd05","sourceURL":"https://devmystify.com/blog/top-6-validation-libraries-for-javascript-in-2025","url":"https://devmystify.com/blog/top-6-validation-libraries-for-javascript-in-2025","statusCode":200,"contentType":"text/html; charset=utf-8","proxyUsed":"basic","cacheState":"hit","cachedAt":"2026-03-29T11:20:45.870Z","creditsUsed":1}},{"url":"https://www.reddit.com/r/typescript/comments/1kaibjf/whats_your_experience_with_superstruct/","title":"What's your experience with Superstruct? : r/typescript - Reddit","description":"Zod/Superstruct work great for defining types that you don't necessarily control. Also they have a more ergonomic \"validation\" constructor API, ...","position":3},{"url":"https://dev.to/dzakh/javascript-schema-library-from-the-future-5420","title":"JavaScript schema library from the Future - DEV Community","description":"There are dozens of such libraries, and the most popular ones are Zod, Valibot, Runtypes, Arktype, Typia, Superstruct, Effect Schema, and more.","position":4,"markdown":"[ReScript Schema](https://github.com/DZakh/rescript-schema) \\- The fastest parser in the entire JavaScript ecosystem with a focus on small bundle size and top-notch DX.\n\nWhy did you not hear about it then, and why should you learn about it now? I started developing the library three years ago, and today, it's at a point others have yet to achieve. I'll prove it in the article, but before we start, I'd like to answer a few questions you might already have.\n\n### What's a parser?\n\nOne of the most basic applications of ReScript Schema is parsing - Accepting unknown JavaScript data, validating it, and returning the result of your desired type. There are dozens of such libraries, and the most popular ones are [Zod](https://github.com/colinhacks/zod), [Valibot](https://github.com/fabian-hiller/valibot), [Runtypes](https://github.com/runtypes/runtypes), [Arktype](https://github.com/arktypeio/arktype), [Typia](https://github.com/samchon/typia), [Superstruct](https://github.com/ianstormtaylor/superstruct), [Effect Schema](https://github.com/Effect-TS/schema), and more. Also, even though this is slightly different, validation libraries like [Ajv](https://github.com/ajv-validator/ajv), [Yup](https://github.com/jquense/yup), and others also stand really close.\n\n### Is ReScript Schema faster than all of them?\n\nYes. It's ~100 times faster than [Zod](https://github.com/colinhacks/zod) and on par with [Typia](https://github.com/samchon/typia) or [Arktype](https://github.com/arktypeio/arktype) ( [benchmark](https://moltar.github.io/typescript-runtime-type-benchmarks/)). But often, besides validation, you want to transform data incoming to your system, and here, ReScript Schema overperforms any solution existing in the JavaScript ecosystem.\n\n### What's ReScript? Isn't the library for JavaScript/TypeScript?\n\n[ReScript](https://rescript-lang.org/) is a robustly typed language that compiles to efficient and human-readable JavaScript. And yes, ReScript Schema is written in ReScript, but it also has a really nice JavaScript API with TS types. You don't need to install or run any compiler; `npm i rescript-schema` is all you need.\n\nIt makes ReScript Schema support 3 languages - JavaScript, TypeScript, and ReScript. This is especially nice when you mix TypeScript and ReScript in a single codebase 👌\n\n### Are there trade-offs?\n\nYes. To maximize DX, performance, and bundle size while keeping the library fully runtime, I've decided to use [eval](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval) under the hood. You needn't worry about the code's dangerous execution, but some environments, like Cloudflare Workers, won't work. In 99% of cases, you don't need to be concerned about this. I just think it's my duty as a creator to let you know about the 1% beforehand.\n\n### What's the plan?\n\nI'm going to provide an overview of the basic ReScript Schema API and mental model. Then, we'll discuss what makes it stand out from millions of similar libraries (and this is not only performance). I'll also look at some more advanced use cases and discuss the ecosystem, performance, and where it stands with other libraries.\n\nI hope you'll enjoy it. 😊\n\n> Follow me on [X](https://x.com/dzakh_dev) to learn more about programming stuff I'm cooking.\n\n## Parsing / Validating\n\nLet's start with the most basic use case of ReScript Schema. By the way, if you don't know the difference between parsing (sometimes called decoding) and validating, here's a [good article](https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/) from Zod's docs. If you're curious about when and why you need to parse data in your application, let me know in the comments. I can write a big article about it, but for now, I assume you are already familiar with the concept.\n\nLet's finally take a look at the code. I'll go with the TypeScript example first, so it's more familiar for most readers. Everything starts with defining a schema of the data you expect:\n\n```\nimport * as S from \"rescript-schema\";\n\nconst filmSchema = S.schema({\n id: S.number,\n title: S.string,\n tags: S.array(S.string),\n rating: S.union([\"G\", \"PG\", \"PG13\", \"R\"])\n})\n```\n\nEnter fullscreen modeExit fullscreen mode\n\nThe schema here is like a type definition that exists in runtime. If you hover over the `filmSchema`, you'll see the following type:\n\n```\nS.Schema<{\n id: number;\n title: string;\n tags: string[];\n rating: \"G\" | \"PG\" | \"PG13\" | \"R\";\n}>\n```\n\nEnter fullscreen modeExit fullscreen mode\n\nThis is a `Schema` type that inferred the film object definition. I recommend extracting its value into its own type. This way, you'll have the schema as the source of truth and the `Film` type always matching the schema:\n\n```\ntype Film = S.Output\n```\n\nEnter fullscreen modeExit fullscreen mode\n\nAfter we've defined our `Film` type using the schema, we can parse unknown data entering our application to guarantee that it matches what we expect:\n\n```\nS.parseOrThrow(\n {\n id: 1,\n title: \"My first film\",\n tags: [\"Loved\"],\n rating: \"S\",\n },\n filmSchema,\n);\n//? Throws RescriptSchemaError with message `Failed parsing at [\"rating\"]. Reason: Expected \"G\" | \"PG\" | \"PG13\" | \"R\", received \"S\"`\n\nS.parseOrThrow(validDataWithUnknownType, filmSchema)\n//? Returns value of the Film type\n\n// If you don't want to throw, you can wrap the operations in S.safe and get S.Result as a return value\nS.safe(() => S.parseOrThrow(data, filmSchema))\n```\n\nEnter fullscreen modeExit fullscreen mode\n\nDone! We have valid data here 🙌\n\nSome experienced users may have noticed that the API is similar to [Valibot](https://github.com/fabian-hiller/valibot), but with a unique flavor.\n\nYou can use `S.schema` for objects, tuples, and literals. For any kind of union, there's `S.union`; even if it's a [discriminated](https://github.com/DZakh/rescript-schema/blob/main/docs/js-usage.md#discriminated-unions) one, the parser will perform in the most optimized way. I personally have seen this kind of DX only in [ArkType](https://arktype.io/) so far.\n\nAlso, there are no annoying parentheses; the parse function explicitly says it can throw, and thanks to the modular design, the library tree-shaking is very good.\n\n### Package size\n\nSince I mentioned tree-shaking, I'd like to quickly note about the package size. The bundle size is an essential metric for a web application, and I'd like to share how ReScript Schema is doing here in comparison with other libraries:\n\n| | [rescript-schema@9.2.2](mailto:rescript-schema@9.2.2) | [Zod@3.24.1](mailto:Zod@3.24.1) | [Valibot@1.0.0-beta.14](mailto:Valibot@1.0.0-beta.14) | [ArkType@2.0.4](mailto:ArkType@2.0.4) |\n| --- | --- | --- | --- | --- |\n| **Total size** (minified + gzipped) | 12.7 kB | 15.2 kB | 12.3 kB | 40.8 kB |\n| **Example size** (minified + gzipped) | 5.14 kB | 14.5 kB | 1.39 kB | 40.7 kB |\n| **Playground** | [Link](https://bundlejs.com/?q=rescript-schema%409.2.2&treeshake=%5B*%5D&text=%22const+filmSchema+%3D+S.schema%28%7B%5Cn++id%3A+S.number%2C%5Cn++title%3A+S.string%2C%5Cn++tags%3A+S.array%28S.string%29%2C%5Cn++rating%3A+S.union%28%5B%5C%22G%5C%22%2C+%5C%22PG%5C%22%2C+%5C%22PG13%5C%22%2C+%5C%22R%5C%22%5D%29%2C%5Cn%7D%29%3B%5Cn%5CnS.parseOrThrow%28null%2C+filmSchema%29%22) | [Link](https://bundlejs.com/?q=zod%403.24.1&treeshake=%5B*%5D&text=%22const+filmSchema+%3D+z.object%28%7B%5Cn++id%3A+z.number%28%29%2C%5Cn++title%3A+z.string%28%29%2C%5Cn++tags%3A+z.array%28z.string%28%29%29%2C%5Cn++rating%3A+z.enum%28%5B%5C%22G%5C%22%2C+%5C%22PG%5C%22%2C+%5C%22PG13%5C%22%2C+%5C%22R%5C%22%5D%29%2C%5Cn%7D%29%3B%5Cn%5CnfilmSchema.parse%28null%29%22) | [Link](https://bundlejs.com/?q=valibot%401.0.0-beta.14&treeshake=%5B*%5D&text=%22const+filmSchema+%3D+v.object%28%7B%5Cn++id%3A+v.number%28%29%2C%5Cn++title%3A+v.string%28%29%2C%5Cn++tags%3A+v.array%28z.string%28%29%29%2C%5Cn++rating%3A+v.picklist%28%5B%5C%22G%5C%22%2C+%5C%22PG%5C%22%2C+%5C%22PG13%5C%22%2C+%5C%22R%5C%22%5D%29%2C%5Cn%7D%29%3B%5Cn%5Cnv.parse%28filmSchema%2C+null%29%22) | [Link](https://bundlejs.com/?q=arktype%402.0.4&treeshake=%5B*%5D&text=%22const+filmSchema+%3D+type%28%7B%5Cn++id%3A+%5C%22number%5C%22%2C%5Cn++title%3A+%5C%22string%5C%22%2C%5Cn++tags%3A+%5C%22string%5B%5D%5C%22%2C%5Cn++rating%3A+%60%5C%22G%5C%22+%7C+%5C%22PG%5C%22+%7C+%5C%22PG13%5C%22+%7C+%5C%22R%5C%22%60%2C%5Cn%7D%29%3B%5Cn%5CnfilmSchema%28null%29%22) |\n\nIt's not as amazing as Valibot, but ReScript Schema is definitely doing good here. If we compare ReScript Schema to libraries that have similar performance, they all use the code generation approach (besides ArkType). This means it'll start small, but for every new type, more and more code will be added to your bundle, rapidly increasing the application size.\n\n### Parsing using ReScript\n\nEven though I want to make ReScript Schema popular for TS developers, ReScript is still the library's main user base, so I'll also include examples of it.\n\nCompared to TypeScript, the type system in ReScript is much simpler; you literally can't do any type gymnastics in it. Together with [nominal typing](https://medium.com/@thejameskyle/type-systems-structural-vs-nominal-typing-explained-56511dd969f4), it's getting impossible to extract the `film` type from the schema (even though it can infer it). But there's a built-in way to prevent boilerplate code in ReScript. You can use ReScript Schema PPX to generate schemas for your types automatically. Just annotate them with `@schema` attribute.\n\n```\n@schema\ntype rating =\n | @as(\"G\") GeneralAudiences\n | @as(\"PG\") ParentalGuidanceSuggested\n | @as(\"PG13\") ParentalStronglyCautioned\n | @as(\"R\") Restricted\n@schema\ntype film = {\n id: float,\n title: string,\n tags: array,\n rating: rating,\n}\n```\n\nEnter fullscreen modeExit fullscreen mode\n\nDoes the `rating` type look scary to you? Don't worry, this is a ReScript [Variant](https://rescript-lang.org/docs/manual/v11.0.0/variant), which is such a nice way to describe any kind of union. Also, you can use `@as` and give a better name to the ratings while preserving the original short values in runtime.\n\nAlthough PPX is nice, you can always code without it:\n\n```\ntype rating =\n | @as(\"G\") GeneralAudiences\n | @as(\"PG\") ParentalGuidanceSuggested\n | @as(\"PG13\") ParentalStronglyCautioned\n | @as(\"R\") Restricted\ntype film = {\n id: float,\n title: string,\n tags: array,\n rating: rating,\n}\n\nlet filmSchema = S.schema(s => {\n id: s.matches(S.number),\n title: s.matches(S.string),\n tags: s.matches(S.array(S.string)),\n rating: s.matches(S.union([\\\n GeneralAudiences,\\\n ParentalGuidanceSuggested,\\\n ParentalStronglyCautioned,\\\n Restricted\\\n ]))\n})\n```\n\nEnter fullscreen modeExit fullscreen mode\n\nThe TS API admittedly wins here since we don't need to call `s.matches` to make type system happy, but when it comes to parsing ReScript takes it back with the [Pipe Operator](https://rescript-lang.org/docs/manual/v11.0.0/pipe) and [Pattern Matching on exceptions](https://rescript-lang.org/docs/manual/v11.0.0/pattern-matching-destructuring#match-on-exceptions):\n\n```\n{\n \"id\": 1,\n \"title\": \"My first film\",\n \"tags\": [\"Loved\"],\n \"rating\": \"S\",\n}->S.parseOrThrow(filmSchema)\n//? Throws RescriptSchemaError with message `Failed parsing at [\"rating\"]. Reason: Expected \"G\" | \"PG\" | \"PG13\" | \"R\", received \"S\"`\n\nvalidDataWithUnknownType->S.parseOrThrow(filmSchema)\n//? Returns value of the film type\n\n// If you don't want to throw, you can match on the S.Raised exception and return the result type. There's no S.safe API like in TypeScript, since you can do better with the language itself!\nswitch data->S.parseOrThrow(filmSchema) {\n| film => Ok(film)\n| exception S.Raised(error) => Error(error)\n}\n```\n\nEnter fullscreen modeExit fullscreen mode\n\n## Unique Features\n\nAfter we covered the most basic use case, let's move on to the things that make ReScript Schema special 🔥\n\n### Changing shape and field names\n\nLet's imagine working with a weird REST API with poorly named fields in PascalCase, where data is randomly nested in objects or tuples. But we can't change the backend, so at least we want to transform data to a more convenient format for our application. In ReScript Schema you can make it in a declarative way, which will result in the most possibly performant operation:\n\n```\nconst filmSchema = S.object((s) => ({\n id: s.field(\"Id\", S.number),\n title: s.nested(\"Meta\").field(\"Title\", S.string),\n tags: s.field(\"Tags_v2\", S.array(S.string)),\n rating: s.field(\"Rating\", S.schema([S.union([\"G\", \"PG\", \"PG13\", \"R\"])]))[0],\n}));\n\nS.parseOrThrow(\n {\n Id: 1,\n Meta: {\n Title: \"My first film\",\n },\n Tags_v2: [\"Loved\"],\n Rating: [\"G\"],\n },\n filmSchema\n);\n//? { id: 1, title: \"My first film\", tags: [\"Loved\"], rating: \"G\" }\n```\n\nEnter fullscreen modeExit fullscreen mode\n\nLooks scary? Let's dive in. First of all, every schema has `Input` and `Output`. Quite often, they are equal, and during parsing, the library only validates that `Input` has the correct type and returns it immediately. Although there are ways to change the expected `Output` type like we do in the example above. For comparison, let's take a look at how you'd usually achieve the same with other schema libraries:\n\n```\nconst filmSchema = S.transform(\n S.schema({\n Id: S.number,\n Meta: {\n Title: S.string,\n },\n Tags_v2: S.array(S.string),\n Rating: S.schema([S.union([\"G\", \"PG\", \"PG13\", \"R\"])]),\n }),\n (input) => ({\n id: input.Id,\n title: input.Meta.Title,\n tags: input.Tags_v2,\n rating: input.Rating[0],\n })\n);\n```\n\nEnter fullscreen modeExit fullscreen mode\n\nThis is still ReScript Schema, but we use `S.transform` to manually transform the `Input` type. You can find this kind of API in many other schema libraries. What's good about the example is that you can clearly see that we use our schema to declaratively describe what the data incoming to our system looks like, and then we transform it to what's convenient for us to work with. In a way, the schema here is similar to a contract between the client and the server that returns the object in response.\n\nIn the advanced `S.object` example, which I showed first, we combine a declarative description of the `Input` type with a transformation to the `Output` type. And this enables one more thing besides shorter code and a performance boost.\n\n### Reverse Parsing (aka serializing/decoding)\n\nDecoding is present in many libraries from other languages, but it's not very common in the JS ecosystem. This is a big loss because the ability to perform operations in the reverse direction is the most powerful feature I personally find.\n\nIf it's unclear what I mean, in other popular JavaScript schema libraries, you can only parse `Input` to `Output` types. While in ReScript Schema you can easily parse `Output` to `Input` using the same schema. Or only perform the conversion logic since the `Output` type usually doesn't require validation.\n\nDo you remember our `filmSchema` using `S.object` to rename fields? Let's say we want to send a POST request with the film entity, and the server also expects the weirdly cased data structure it initially sent to us. Here is how we deal with it:\n\n```\n// The same schema from above\nconst filmSchema = S.object((s) => ({\n id: s.field(\"Id\", S.number),\n title: s.nested(\"Meta\").field(\"Title\", S.string),\n tags: s.field(\"Tags_v2\", S.array(S.string)),\n rating: s.field(\"Rating\", S.schema([S.union([\"G\", \"PG\", \"PG13\", \"R\"])]))[0],\n}));\n\nS.reverseConvertOrThrow({ id: 1, title: \"My first film\", tags: [\"Loved\"], rating: \"G\" }, filmSchema)\n//? { Id: 1, Meta: { Title: \"My first film\" }, Tags_v2: [\"Loved\"], Rating: [\"G\"] }\n```\n\nEnter fullscreen modeExit fullscreen mode\n\nSweet! Isn't it? And even though I want to talk more about performance a little bit later, I can't stop myself from sharing the code it evaluates under the hood:\n\n```\n(i) => {\n let v0 = i[\"tags\"];\n return {\n Id: i[\"id\"],\n Meta: { Title: i[\"title\"] },\n Tags_v2: v0,\n Rating: [i[\"rating\"]],\n };\n};\n```\n\nEnter fullscreen modeExit fullscreen mode\n\nI think most people would write slower code by hand 😅\n\n### Reverse\n\nThe `S.reverseConvertOrThrow` is one of the reverse cases I use daily in my work, but this is actually just a shorthand of `S.convertOrThrow` and `S.reverse` you can use separately.\n\n`S.reverse` \\- this is what allows you to take your `Schema` and turn it into `Schema`.\n\nIt may sound quite dull, but compared to the commonly used parser/serializer or encoder/decoder approach, here you get an actual schema you can use the same way as the original one without any limitations.\n\nIf you want, you can parse output with/without data validation, generate JSON Schema, perform optimized comparison and hashing, or use the data representation in runtime for any custom logic.\n\nAs a fruit of the ability to know `Input` and `Output` data types in runtime, ReScript Schema has a very powerful coercion API.\n\n```\nconst schema = S.coerce(S.string, S.bigint)\nS.parseOrThrow(\"123\", schema) //? 123n\nS.reverseConvertOrThrow(123n, schema) //? \"123\"\n```\n\nEnter fullscreen modeExit fullscreen mode\n\nPass any schemas to `S.coerce` that you want to coerce from and to, and ReScript Schema will figure out the rest.\n\nAnd this has not been implemented yet, but with the API, it'll also be possible to achieve 2x faster JSON.stringify(). Like [fast-json-stringify](https://github.com/fastify/fast-json-stringify) does and maybe even faster 😎\n\n### 100 Operations\n\nIf you want the best possible performance or the built-in operations don't cover your specific use case, you can use `S.compile` to create fine-tuned operation functions.\n\n```\nconst operation = S.compile(S.string, \"Any\", \"Assert\", \"Async\");\n//? (input: unknown) => Promise\n\nawait operation(\"Hello world!\");\n```\n\nEnter fullscreen modeExit fullscreen mode\n\nIn the example above, we've created an async assert operation, which is not available by default.\n\nWith the API, you can get 100 different operation combinations, each of which might make sense for your specific use case. This is like [parser](https://valibot.dev/api/parser/) in Valibot, but multiplied by 💯.\n\n### Performance Comparison\n\nAs I mentioned in the beginning, ReScript Schema is the fastest. Now I'll explain why 🔥\n\nAlso, you can use the big community [benchmark](https://moltar.github.io/typescript-runtime-type-benchmarks/) to confirm yourself. If you see [Typia](https://typia.io/) overperforming ReScript Schema, I have a take on it too 😁\n\nFirst of all, the biggest advantage of ReScript Schema is its very clever library core, which builds the most possibly optimized operations using `eval`. I have already shown before how the operation code looks for reverse conversion; here's the `filmSchema` parse operation code:\n\n```\n(i) => {\n if (typeof i !== \"object\" || !i) {\n e[7](i);\n }\n let v0 = i[\"Id\"],\n v1 = i[\"Meta\"],\n v3 = i[\"Tags_v2\"],\n v7 = i[\"Rating\"];\n if (typeof v0 !== \"number\" || Number.isNaN(v0)) {\n e[0](v0);\n }\n if (typeof v1 !== \"object\" || !v1) {\n e[1](v1);\n }\n let v2 = v1[\"Title\"];\n if (typeof v2 !== \"string\") {\n e[2](v2);\n }\n if (!Array.isArray(v3)) {\n e[3](v3);\n }\n for (let v4 = 0; v4 < v3.length; ++v4) {\n let v6 = v3[v4];\n try {\n if (typeof v6 !== \"string\") {\n e[4](v6);\n }\n } catch (v5) {\n if (v5 && v5.s === s) {\n v5.path = '[\"Tags_v2\"]' + '[\"' + v4 + '\"]' + v5.path;\n }\n throw v5;\n }\n }\n if (!Array.isArray(v7) || v7.length !== 1) {\n e[5](v7);\n }\n let v8 = v7[\"0\"];\n if (v8 !== \"G\") {\n if (v8 !== \"PG\") {\n if (v8 !== \"PG13\") {\n if (v8 !== \"R\") {\n e[6](v8);\n }\n }\n }\n }\n return { id: v0, title: v2, tags: v3, rating: v8 };\n};\n```\n\nEnter fullscreen modeExit fullscreen mode\n\nThanks to `eval`, we can eliminate function calls and inline all type validations using `if` statements. Also, knowing about the `Output` type at runtime allows us to perform transformations with zero wasteful object allocations, optimizing the operation for JavaScript engines.\n\nInterestingly, you probably think that calling `eval` itself is slow, and I thought this myself. However, it was actually not as slow as I expected. For example, creating a simple nested object schema and calling the parser once happened to be 1.8 times faster with ReScript Schema using eval than Zod. I really put a lot of effort into making it as fast as possible, and I have to thank the [ReScript language](https://rescript-lang.org/) and the people behind it for allowing me to write very performant and safe code.\n\nTalking about [ArkType](https://arktype.io/), they use the same approach with eval and have similar potential to ReScript Schema, but their evaluated code is not there yet. Currently, their operations are a little bit slower, and the schema creation is significantly slower. But I can see that it can somewhat catch up in the future.\n\nWhat other libraries will never be able to catch up on is the ability to reshape schema declaratively. And this is why I say that ReScript Schema is faster than Typia. Also, Typia doesn't always generate the most optimized code, e.g., for optional fields. And it doesn't come with many built-in operations specifically optimized for the desired use case. Still, this is an excellent library with Fast JSON Serialization and Protocol Buffer Encoding features, which I'm still yet to implement.\n\n### Ecosystem\n\nWhen choosing a schema library for your project, where performance is not a concern, the ecosystem is the most important factor to consider. With a schema, you can do millions of things by knowing the type of representation in runtime. Such as JSON Schema generation, describing database schemas, optimized comparison and hashing, encoding to proto buff, building forms, mocking data, communicating with AI, and much more.\n\nZod is definitely a winner here. I counted 78 libraries integrating with Zod at the moment of writing the article. There are even some where you provide a Zod schema, and it renders a Vue page with a form prompting for the data. This is just too convenient for not using it for prototyping.\n\nBut if you don't need something super specific, ReScript Schema has a decent ecosystem itself, which is comparable to Valibot and ArkType. Actually, it has an even higher potential thanks to the ability to adjust Shape and automatically Reverse the schema. A good example of this is [ReScript Rest](https://github.com/DZakh/rescript-rest), which combines the DX of [tRPC](https://trpc.io/) while staying unopinionated like [ts-rest](https://ts-rest.com/). I also built many powerful tools around ReScript Schema, but I have to admit that I haven't added TS support yet. Let me know if you find something interesting to use, and I'll do this asap 😁\n\nAlso, ReScript Schema supports [Standard Schema](https://standardschema.dev/), a common interface for TypeScript validation libraries. It was recently designed by the creators of Zod, Valibot, and ArkType and has already been integrated into many popular libraries. This means that you can use ReScript Schema with [tRPC](https://trpc.io/), [TanStack Form](https://tanstack.com/form), [TanStack Router](https://tanstack.com/router), [Hono](https://hono.dev/), and 19+ more at the time of writing the article.\n\n### Conclusion\n\nAs the title says, I wholeheartedly believe that ReScript Schema is the future of schema libraries. It offers both DX, performance, bundle size, and many innovative features. I tried to cover all of them at a high level, and I hope I managed to make you at least a little bit interested 👌\n\nI don't persuade you to choose ReScript Schema for your next project, and I actually still recommend Zod when somebody asks me. But I'll definitely appreciate a [star](https://github.com/DZakh/rescript-schema) and [X follow](https://x.com/dzakh_dev) 🙏\n\nLet's see how the future of schema libraries will turn out. Maybe I'll rename ReScript Schema to something dope and become more popular than Zod? Cheers 😁\n\n[![profile](https://media2.dev.to/dynamic/image/width=64,height=64,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F140%2F9639a040-3c27-4b99-b65a-85e100016d3c.png)\\\\\nMongoDB](https://dev.to/mongodb) Promoted\n\nDropdown menu\n\n- [What's a billboard?](https://dev.to/billboards)\n- [Manage preferences](https://dev.to/settings/customization#sponsors)\n\n* * *\n\n- [Report billboard](https://dev.to/report-abuse?billboard=241241)\n\n[![Gen AI apps are built with MongoDB Atlas](https://media2.dev.to/dynamic/image/width=775%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FlGiI0TQ.png)](https://www.mongodb.com/cloud/atlas/lp/try3?utm_campaign=display_devto-broad_pl_flighted_atlas_tryatlaslp_prosp_gic-null_ww-all_dev_dv-all_eng_leadgen&utm_source=devto&utm_medium=display&utm_content=airevolution-v1&bb=241241)\n\n## [Gen AI apps are built with MongoDB Atlas](https://www.mongodb.com/cloud/atlas/lp/try3?utm_campaign=display_devto-broad_pl_flighted_atlas_tryatlaslp_prosp_gic-null_ww-all_dev_dv-all_eng_leadgen&utm_source=devto&utm_medium=display&utm_content=airevolution-v1&bb=241241)\n\nMongoDB Atlas is the developer-friendly database for building, scaling, and running gen AI & LLM apps—no separate vector DB needed. Enjoy native vector search, 115+ regions, and flexible document modeling. Build AI faster, all in one place.\n\n[Start Free](https://www.mongodb.com/cloud/atlas/lp/try3?utm_campaign=display_devto-broad_pl_flighted_atlas_tryatlaslp_prosp_gic-null_ww-all_dev_dv-all_eng_leadgen&utm_source=devto&utm_medium=display&utm_content=airevolution-v1&bb=241241)\n\nRead More\n\n\n![pic](https://media2.dev.to/dynamic/image/width=256,height=,fit=scale-down,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8j7kvp660rqzt99zui8e.png)\n\n[Create template](https://dev.to/settings/response-templates)\n\nTemplates let you quickly answer FAQs or store snippets for re-use.\n\nSubmitPreview [Dismiss](https://dev.to/404.html)\n\nCollapseExpand\n\n[![1ce profile image](https://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2337256%2F40090106-5ee4-4298-853e-14ce37ba5350.png)](https://dev.to/1ce)\n\n[Sby](https://dev.to/1ce)\n\nSby\n\n\n\n[![](https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2337256%2F40090106-5ee4-4298-853e-14ce37ba5350.png)\\\\\nSby](https://dev.to/1ce)\n\nFollow\n\nI write good code.\nInterested in moving to another country.\n\n\n- Joined\n\n\nNov 3, 2024\n\n\n• [Feb 22 '25](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2m16g)\n\nDropdown menu\n\n- [Copy link](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2m16g)\n- Hide\n\n- [Report abuse](https://dev.to/report-abuse?url=https://dev.to/1ce/comment/2m16g)\n\nNice work! Definitely will consider it next time I need a parser or a validator.\n\nBy the way, since you're familiar with Typia, have you by any chance seen a recent post by Typia's author about its performance with the Bun runtime being 20 times slower?\n\nWould you perhaps have any comments on that? I'm also interested in how ReScript Schema performs with different runtimes (Node, Deno, Bun, browser)\n\nCollapseExpand\n\n[![dzakh profile image](https://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F988236%2Fbe515a70-aadf-48ea-ba1f-e92410a78528.jpeg)](https://dev.to/dzakh)\n\n[Dmitry Zakharov](https://dev.to/dzakh)\n\nDmitry Zakharov\n\n\n\n[![](https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F988236%2Fbe515a70-aadf-48ea-ba1f-e92410a78528.jpeg)\\\\\nDmitry Zakharov](https://dev.to/dzakh)\n\nFollow\n\nBuild fastest tools with best DX 🫡\n\n\n- Location\n\n\n\nGeorgia, Batumi\n\n\n- Work\n\n\n\nEnvio\n\n\n- Joined\n\n\nDec 11, 2022\n\n\n• [Feb 23 '25](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2m19p)\n\nDropdown menu\n\n- [Copy link](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2m19p)\n- Hide\n\n- [Report abuse](https://dev.to/report-abuse?url=https://dev.to/dzakh/comment/2m19p)\n\nInteresting, this is a new one. Just read it and left a like [dev.to/samchon/bun-is-up-to-20x-sl...](https://dev.to/samchon/bun-is-up-to-20x-slower-than-nodejs-in-logic-operations-305d)\n\nNode.js, Deno and Browser are fine; the only problem is with Bun, which you can see in the community benchmark [moltar.github.io/typescript-runtim...](https://moltar.github.io/typescript-runtime-type-benchmarks)\n\nI can see many comments in the article where people claim that it's a Typia specific problem, but Typia is a codegen library, and it doesn't do anything special in runtime. This means if you write a function like `(input) => \"string\" === typeof input` by hand and run it multiple times, it'll execute multiple times slower in Bun than in any other runtime.\n\nCollapseExpand\n\n[![retakenroots profile image](https://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F814218%2F618df07d-caf8-41a4-b026-c52ffbe8b21b.png)](https://dev.to/retakenroots)\n\n[Rene Kootstra](https://dev.to/retakenroots)\n\nRene Kootstra\n\n\n\n[![](https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F814218%2F618df07d-caf8-41a4-b026-c52ffbe8b21b.png)\\\\\nRene Kootstra](https://dev.to/retakenroots)\n\nFollow\n\nAuthor of enge-js a pure JavaScript playstation 1 emulator and professional developer for 25+ years.\n\n\n- Joined\n\n\nFeb 12, 2022\n\n\n• [Feb 23 '25](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2m1a7)\n\nDropdown menu\n\n- [Copy link](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2m1a7)\n- Hide\n\n- [Report abuse](https://dev.to/report-abuse?url=https://dev.to/retakenroots/comment/2m1a7)\n\nHmm very interesting article. Though when i read eval it raised some concerns. Nonetheless good job.\n\nCollapseExpand\n\n[![dzakh profile image](https://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F988236%2Fbe515a70-aadf-48ea-ba1f-e92410a78528.jpeg)](https://dev.to/dzakh)\n\n[Dmitry Zakharov](https://dev.to/dzakh)\n\nDmitry Zakharov\n\n\n\n[![](https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F988236%2Fbe515a70-aadf-48ea-ba1f-e92410a78528.jpeg)\\\\\nDmitry Zakharov](https://dev.to/dzakh)\n\nFollow\n\nBuild fastest tools with best DX 🫡\n\n\n- Location\n\n\n\nGeorgia, Batumi\n\n\n- Work\n\n\n\nEnvio\n\n\n- Joined\n\n\nDec 11, 2022\n\n\n• [Feb 23 '25](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2m1ac)\n\nDropdown menu\n\n- [Copy link](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2m1ac)\n- Hide\n\n- [Report abuse](https://dev.to/report-abuse?url=https://dev.to/dzakh/comment/2m1ac)\n\nIt's indeed good to be aware of this because if you build for serverless or some widget that is embedded as a CDN to someone else website ( [CSP](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP)) there might be problems. But as I said, this is ~1% of use cases.\n\nAlso, ArkType uses eval, and according to [Colin](https://x.com/colinhacks)'s words, he plans to add Eval mode to Zod v4.\n\nIdeally, there should be a fallback mode to be able to work without Eval when it's not supported. I actually recently got an idea of how to implement it without reducing the quality of the library. But it'll probably take several months for me to implement.\n\nCollapseExpand\n\n[![dhruvgarg79 profile image](https://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F240393%2F20a5c1d2-440e-4ecc-8625-c5d578a6ab7d.jpeg)](https://dev.to/dhruvgarg79)\n\n[Dhruv garg](https://dev.to/dhruvgarg79)\n\nDhruv garg\n\n\n\n[![](https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F240393%2F20a5c1d2-440e-4ecc-8625-c5d578a6ab7d.jpeg)\\\\\nDhruv garg](https://dev.to/dhruvgarg79)\n\nFollow\n\nWorking as a Tech Lead at a MarTech Startup.\nInterested in Databases, Performance, and everything Backend.\n\n\n- Location\n\n\n\nBengaluru, India\n\n\n- Education\n\n\n\nB. Tech in computer science\n\n\n- Work\n\n\n\nTech lead\n\n\n- Joined\n\n\nOct 1, 2019\n\n\n• [Feb 25 '25](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2m2lh)\n\nDropdown menu\n\n- [Copy link](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2m2lh)\n- Hide\n\n- [Report abuse](https://dev.to/report-abuse?url=https://dev.to/dhruvgarg79/comment/2m2lh)\n\nwhat about comparison with typebox? It's also much faster than zod.\n\nCollapseExpand\n\n[![dzakh profile image](https://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F988236%2Fbe515a70-aadf-48ea-ba1f-e92410a78528.jpeg)](https://dev.to/dzakh)\n\n[Dmitry Zakharov](https://dev.to/dzakh)\n\nDmitry Zakharov\n\n\n\n[![](https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F988236%2Fbe515a70-aadf-48ea-ba1f-e92410a78528.jpeg)\\\\\nDmitry Zakharov](https://dev.to/dzakh)\n\nFollow\n\nBuild fastest tools with best DX 🫡\n\n\n- Location\n\n\n\nGeorgia, Batumi\n\n\n- Work\n\n\n\nEnvio\n\n\n- Joined\n\n\nDec 11, 2022\n\n\n• [Feb 26 '25](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2m300)\n\nDropdown menu\n\n- [Copy link](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2m300)\n- Hide\n\n- [Report abuse](https://dev.to/report-abuse?url=https://dev.to/dzakh/comment/2m300)\n\nThis is actually very good, and it's very mature. I actually had a misunderstanding about it being a worse version of Typia, but after double-checking the docs, I was really impressed by it.\n\nIn the benchmark, you can indeed see that it's fast [moltar.github.io/typescript-runtim...](https://moltar.github.io/typescript-runtime-type-benchmarks/)\n\nBut there are some trade-offs that are solved in ReScript Schema:\n\n- Optimised check only supports validation, not parsing with data transformations\n- I find the DX of ReScript Schema to be more friendly for web developers. Also, reshaping and reversing are still unbeaten\n- The TypeBox packages size is huge, making it not the best fit for web development [github.com/sinclairzx81/typebox?ta...](https://github.com/sinclairzx81/typebox?tab=readme-ov-file#compression)\n\nSo, at the moment of writing the article I think ReScript Schema is a better library if you use it for Web, but for server-side TypeBox is more mature and provides more flexibility and features. Although there are still some features of ReScript Schema you might want to use, which are not a part of TypeBox 😉\n\nReScript Schema v10 is coming, which will improve the flexibility similar to TypeBox while boosting DX even more, exceeding Zod and ArkType levels 😁\n\nCollapseExpand\n\n[![dzakh profile image](https://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F988236%2Fbe515a70-aadf-48ea-ba1f-e92410a78528.jpeg)](https://dev.to/dzakh)\n\n[Dmitry Zakharov](https://dev.to/dzakh)\n\nDmitry Zakharov\n\n\n\n[![](https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F988236%2Fbe515a70-aadf-48ea-ba1f-e92410a78528.jpeg)\\\\\nDmitry Zakharov](https://dev.to/dzakh)\n\nFollow\n\nBuild fastest tools with best DX 🫡\n\n\n- Location\n\n\n\nGeorgia, Batumi\n\n\n- Work\n\n\n\nEnvio\n\n\n- Joined\n\n\nDec 11, 2022\n\n\n• [Feb 26 '25](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2m305)\n\nDropdown menu\n\n- [Copy link](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2m305)\n- Hide\n\n- [Report abuse](https://dev.to/report-abuse?url=https://dev.to/dzakh/comment/2m305)\n\nOk, I decided to double-check the package size table from their docs and it actually happened that the package size is not big [bundlephobia.com/package/@sinclair...](https://bundlephobia.com/package/@sinclair/typebox@0.34.28)\n\nAnother thing to compare is the much more readable error messages by default in ReScript Schema.\n\n[![dhruvgarg79 profile image](https://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F240393%2F20a5c1d2-440e-4ecc-8625-c5d578a6ab7d.jpeg)](https://dev.to/dhruvgarg79)\n\n[Dhruv garg](https://dev.to/dhruvgarg79)\n\nDhruv garg\n\n\n\n[![](https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F240393%2F20a5c1d2-440e-4ecc-8625-c5d578a6ab7d.jpeg)\\\\\nDhruv garg](https://dev.to/dhruvgarg79)\n\nFollow\n\nWorking as a Tech Lead at a MarTech Startup.\nInterested in Databases, Performance, and everything Backend.\n\n\n- Location\n\n\n\nBengaluru, India\n\n\n- Education\n\n\n\nB. Tech in computer science\n\n\n- Work\n\n\n\nTech lead\n\n\n- Joined\n\n\nOct 1, 2019\n\n\n• [Mar 18 '25](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2meh7)\n\nDropdown menu\n\n- [Copy link](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2meh7)\n- Hide\n\n- [Report abuse](https://dev.to/report-abuse?url=https://dev.to/dhruvgarg79/comment/2meh7)\n\nI will give it a try in near future, thanks for amazing library my friend :)\n\nCollapseExpand\n\n[![alexdev404 profile image](https://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F380997%2F95f1218d-761b-4c74-8d0f-a5c00c64650e.jpeg)](https://dev.to/alexdev404)\n\n[Immanuel Garcia](https://dev.to/alexdev404)\n\nImmanuel Garcia\n\n\n\n[![](https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F380997%2F95f1218d-761b-4c74-8d0f-a5c00c64650e.jpeg)\\\\\nImmanuel Garcia](https://dev.to/alexdev404)\n\nFollow\n\n- Joined\n\n\nMay 6, 2020\n\n\n• [Feb 23 '25](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2m1h4)\n\nDropdown menu\n\n- [Copy link](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2m1h4)\n- Hide\n\n- [Report abuse](https://dev.to/report-abuse?url=https://dev.to/alexdev404/comment/2m1h4)\n\nSo why even use this if you can just use Zod or Valibot, bypassing any or all of that `eval` magic you did just for a few extra kilobytes?\n\nCollapseExpand\n\n[![dzakh profile image](https://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F988236%2Fbe515a70-aadf-48ea-ba1f-e92410a78528.jpeg)](https://dev.to/dzakh)\n\n[Dmitry Zakharov](https://dev.to/dzakh)\n\nDmitry Zakharov\n\n\n\n[![](https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F988236%2Fbe515a70-aadf-48ea-ba1f-e92410a78528.jpeg)\\\\\nDmitry Zakharov](https://dev.to/dzakh)\n\nFollow\n\nBuild fastest tools with best DX 🫡\n\n\n- Location\n\n\n\nGeorgia, Batumi\n\n\n- Work\n\n\n\nEnvio\n\n\n- Joined\n\n\nDec 11, 2022\n\n\n• [Feb 24 '25• Edited on Feb 24• Edited](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2m1j5)\n\nDropdown menu\n\n- [Copy link](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2m1j5)\n- Hide\n\n- [Report abuse](https://dev.to/report-abuse?url=https://dev.to/dzakh/comment/2m1j5)\n\nEval actually makes the size bigger 😅\n\nThere are some unique features you can't find in any other library together:\n\n- Nice API with good DX\n- Top performance\n- Ability to conveniently and efficiently transform data when you parse\n- Ability to transform data without validation\n- Ability to get schema for the output type\n- Flexible set of operations\n\nIf you don't need it, then use Zod or Valibot. Both of them are good libraries I like.\n\nCollapseExpand\n\n[![jpeggdev profile image](https://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2524181%2F07311901-e943-4cdf-b27d-e1cb1ee4146d.png)](https://dev.to/jpeggdev)\n\n[Jeff Pegg](https://dev.to/jpeggdev)\n\nJeff Pegg\n\n\n\n[![](https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2524181%2F07311901-e943-4cdf-b27d-e1cb1ee4146d.png)\\\\\nJeff Pegg](https://dev.to/jpeggdev)\n\nFollow\n\n- Location\n\n\n\nTulsa, Oklahoma\n\n\n- Joined\n\n\nDec 4, 2024\n\n\n• [Mar 2 '25](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2m5ei)\n\nDropdown menu\n\n- [Copy link](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2m5ei)\n- Hide\n\n- [Report abuse](https://dev.to/report-abuse?url=https://dev.to/jpeggdev/comment/2m5ei)\n\nHi Dmitry, nice article. In your last code example showing the under the hood code, on the 3rd line it says e [7](https://dev.toi/), where does the capital I come from or is that a typo?\n\nCollapseExpand\n\n[![dzakh profile image](https://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F988236%2Fbe515a70-aadf-48ea-ba1f-e92410a78528.jpeg)](https://dev.to/dzakh)\n\n[Dmitry Zakharov](https://dev.to/dzakh)\n\nDmitry Zakharov\n\n\n\n[![](https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F988236%2Fbe515a70-aadf-48ea-ba1f-e92410a78528.jpeg)\\\\\nDmitry Zakharov](https://dev.to/dzakh)\n\nFollow\n\nBuild fastest tools with best DX 🫡\n\n\n- Location\n\n\n\nGeorgia, Batumi\n\n\n- Work\n\n\n\nEnvio\n\n\n- Joined\n\n\nDec 11, 2022\n\n\n• [Mar 2 '25](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2m5f0)\n\nDropdown menu\n\n- [Copy link](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2m5f0)\n- Hide\n\n- [Report abuse](https://dev.to/report-abuse?url=https://dev.to/dzakh/comment/2m5f0)\n\nHm, this looks like a copy-paste bug from Google Docs where I initially written the article. It should be a lower case i. As for `e` it comes from the function context and used for safe embedding to eval code.\n\nCollapseExpand\n\n[![jpeggdev profile image](https://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2524181%2F07311901-e943-4cdf-b27d-e1cb1ee4146d.png)](https://dev.to/jpeggdev)\n\n[Jeff Pegg](https://dev.to/jpeggdev)\n\nJeff Pegg\n\n\n\n[![](https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2524181%2F07311901-e943-4cdf-b27d-e1cb1ee4146d.png)\\\\\nJeff Pegg](https://dev.to/jpeggdev)\n\nFollow\n\n- Location\n\n\n\nTulsa, Oklahoma\n\n\n- Joined\n\n\nDec 4, 2024\n\n\n• [Mar 2 '25](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2m5f6)\n\nDropdown menu\n\n- [Copy link](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2m5f6)\n- Hide\n\n- [Report abuse](https://dev.to/report-abuse?url=https://dev.to/jpeggdev/comment/2m5f6)\n\nI didn't even notice it stripped the brackets and parenthesis from my comment.\n\n`e[7](I)`\n\nCollapseExpand\n\n[![ravi-coding profile image](https://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2029228%2F040177cd-89a9-4e87-a3d2-36cea694274f.png)](https://dev.to/ravi-coding)\n\n[Ravindra Kumar](https://dev.to/ravi-coding)\n\nRavindra Kumar\n\n\n\n[![](https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2029228%2F040177cd-89a9-4e87-a3d2-36cea694274f.png)\\\\\nRavindra Kumar](https://dev.to/ravi-coding)\n\nFollow\n\nFull-Stack Developer \\| MERN & Python \\| Passionate about building web apps and OpenAi APIs. Always learning and sharing knowledge with the community. Let's connect and create something awesome! 🚀\n\n\n- Email\n\n\n[rk2671353@gmail.com](mailto:rk2671353@gmail.com)\n\n- Location\n\n\n\nNew Delhi\n\n\n- Education\n\n\n\n2016\n\n\n- Pronouns\n\n\n\nHe/him\n\n\n- Work\n\n\n\nFull-Stack Developer \\| MERN & Django Specialist \\| Currently enhancing skills in AWS and cloud tech\n\n\n- Joined\n\n\nSep 5, 2024\n\n\n• [Feb 22 '25](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2m0on)\n\nDropdown menu\n\n- [Copy link](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2m0on)\n- Hide\n\n- [Report abuse](https://dev.to/report-abuse?url=https://dev.to/ravi-coding/comment/2m0on)\n\nAwesome !\n\nCollapseExpand\n\n[![jesterly profile image](https://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2844334%2F233844fb-6259-48fc-8959-b3425774dd6d.png)](https://dev.to/jesterly)\n\n[jesterly](https://dev.to/jesterly)\n\njesterly\n\n\n\n[![](https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2844334%2F233844fb-6259-48fc-8959-b3425774dd6d.png)\\\\\njesterly](https://dev.to/jesterly)\n\nFollow\n\n- Joined\n\n\nFeb 10, 2025\n\n\n• [Feb 26 '25](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2m33c)\n\nDropdown menu\n\n- [Copy link](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2m33c)\n- Hide\n\n- [Report abuse](https://dev.to/report-abuse?url=https://dev.to/jesterly/comment/2m33c)\n\nVery cool, and thanks for the heads up about eval. It's a shame we can't use this in browser extensions because eval is not allowed in MV3 :-(.\n\nCollapseExpand\n\n[![dzakh profile image](https://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F988236%2Fbe515a70-aadf-48ea-ba1f-e92410a78528.jpeg)](https://dev.to/dzakh)\n\n[Dmitry Zakharov](https://dev.to/dzakh)\n\nDmitry Zakharov\n\n\n\n[![](https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F988236%2Fbe515a70-aadf-48ea-ba1f-e92410a78528.jpeg)\\\\\nDmitry Zakharov](https://dev.to/dzakh)\n\nFollow\n\nBuild fastest tools with best DX 🫡\n\n\n- Location\n\n\n\nGeorgia, Batumi\n\n\n- Work\n\n\n\nEnvio\n\n\n- Joined\n\n\nDec 11, 2022\n\n\n• [Apr 13 '25](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2n2h8)\n\nDropdown menu\n\n- [Copy link](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#comment-2n2h8)\n- Hide\n\n- [Report abuse](https://dev.to/report-abuse?url=https://dev.to/dzakh/comment/2n2h8)\n\nFinishing V10 with some fantastic improvements. I'm ready to take over the world 😁\n\n![Image description](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F189vmsevh0q432t26c2d.png)\n\n[View full discussion (16 comments)](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420/comments)\n\nAre you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's [permalink](https://dev.to/dzakh/javascript-schema-library-from-the-future-5420#).\n\n\nHide child comments as well\n\nConfirm\n\n\nFor further actions, you may consider blocking this person and/or [reporting abuse](https://dev.to/report-abuse)\n\n[![profile](https://media2.dev.to/dynamic/image/width=64,height=64,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F8431%2F57ccd88f-6269-4347-893f-a0d3f8c5527a.jpg)\\\\\nBright Data](https://dev.to/bright-data) Promoted\n\nDropdown menu\n\n- [What's a billboard?](https://dev.to/billboards)\n- [Manage preferences](https://dev.to/settings/customization#sponsors)\n\n* * *\n\n- [Report billboard](https://dev.to/report-abuse?billboard=246460)\n\n[![Image of Bright Data and n8n Challenge](https://media2.dev.to/dynamic/image/width=775%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fslp0b1u3ff18kt0s5yf3.png)](https://dev.to/joupify/soc-cert-automated-threat-intelligence-system-with-n8n-ai-5722?bb=246460)\n\n## [SOC-CERT: Automated Threat Intelligence System with n8n & AI](https://dev.to/joupify/soc-cert-automated-threat-intelligence-system-with-n8n-ai-5722?bb=246460)\n\nCheck out this submission for the [AI Agents Challenge powered by n8n and Bright Data](https://dev.to/challenges/brightdata-n8n-2025-08-13?bb=246460).\n\n[Read more →](https://dev.to/joupify/soc-cert-automated-threat-intelligence-system-with-n8n-ai-5722?bb=246460)\n\n👋 Kindness is contagious\n\nDropdown menu\n\n- [What's a billboard?](https://dev.to/billboards)\n- [Manage preferences](https://dev.to/settings/customization#sponsors)\n\n* * *\n\n- [Report billboard](https://dev.to/report-abuse?billboard=239338)\n\nx\n\nExplore this practical breakdown on DEV’s open platform, where developers from every background come together to push boundaries. **No matter your experience,** your viewpoint enriches the conversation.\n\nDropping a simple “thank you” or question in the comments goes a long way in supporting authors—your feedback helps ideas evolve.\n\nAt DEV, **shared discovery drives progress** and builds lasting bonds. If this post resonated, a quick nod of appreciation can make all the difference.\n\n## [Okay](https://dev.to/enter?state=new-user&bb=239338)\n\n![DEV Community](https://media2.dev.to/dynamic/image/width=190,height=,fit=scale-down,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8j7kvp660rqzt99zui8e.png)\n\nWe're a place where coders share, stay up-to-date and grow their careers.\n\n\n[Log in](https://dev.to/enter?signup_subforem=1) [Create account](https://dev.to/enter?signup_subforem=1&state=new-user)\n\n![](https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg)![](https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg)![](https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg)![](https://assets.dev.to/assets/raised-hands-74b2099fd66a39f2d7eed9305ee0f4553df0eb7b4f11b01b6b1b499973048fe5.svg)![](https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg)","metadata":{"user-signed-in":"false","keywords":"schema, typescript, rescript, opensource, software, coding, development, engineering, inclusive, community","twitter:site":"@thepracticaldev","head-cached-at":"1774619422","ogImage":"https://media2.dev.to/dynamic/image/width=1000,height=500,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn102ksd9w1xo5ysgxbur.png","application-name":"dev.to","twitter:image:src":"https://media2.dev.to/dynamic/image/width=1000,height=500,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn102ksd9w1xo5ysgxbur.png","environment":"production","forem:name":"DEV Community","forem:logo":"https://media2.dev.to/dynamic/image/width=512,height=,fit=scale-down,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8j7kvp660rqzt99zui8e.png","og:site_name":"DEV Community","language":"en","twitter:creator":"@dzakh_dev","twitter:description":"ReScript Schema - The fastest parser in the entire JavaScript ecosystem with a focus on small bundle...","csrf-token":"Zaxe-092G0zAA0HFwn9lahOGpju8s9tGVoewgHTJx4Nl8W4q4ahTyB3O95CU560sPkhsC6oYVYEdBNbBCMhyPA","og:type":"article","forem:domain":"dev.to","ogDescription":"ReScript Schema - The fastest parser in the entire JavaScript ecosystem with a focus on small bundle...","description":"ReScript Schema - The fastest parser in the entire JavaScript ecosystem with a focus on small bundle... Tagged with schema, typescript, rescript, opensource.","ogSiteName":"DEV Community","og:description":"ReScript Schema - The fastest parser in the entire JavaScript ecosystem with a focus on small bundle...","title":"JavaScript schema library from the Future 🧬 - DEV Community","ogTitle":"JavaScript schema library from the Future 🧬","og:url":"https://dev.to/dzakh/javascript-schema-library-from-the-future-5420","og:image":"https://media2.dev.to/dynamic/image/width=1000,height=500,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn102ksd9w1xo5ysgxbur.png","og:title":"JavaScript schema library from the Future 🧬","last-updated":"2026-03-27 13:50:22 UTC","robots":"max-snippet:-1, max-image-preview:large, max-video-preview:-1","viewport":"width=device-width, initial-scale=1.0, viewport-fit=cover","twitter:widgets:new-embed-design":"on","ogUrl":"https://dev.to/dzakh/javascript-schema-library-from-the-future-5420","theme-color":["#ffffff","#000000"],"twitter:title":"JavaScript schema library from the Future 🧬","csrf-param":"authenticity_token","twitter:card":"summary_large_image","search-script":"https://assets.dev.to/assets/Search-b977aea0f2d7a5818b4ebd97f7d4aba8548099f84f5db5761f8fa67be76abc54.js","apple-mobile-web-app-title":"dev.to","favicon":"https://media2.dev.to/dynamic/image/width=32,height=,fit=scale-down,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8j7kvp660rqzt99zui8e.png","scrapeId":"019d3953-9958-74c3-8f4c-d5e211428a5c","sourceURL":"https://dev.to/dzakh/javascript-schema-library-from-the-future-5420","url":"https://dev.to/dzakh/javascript-schema-library-from-the-future-5420","statusCode":200,"contentType":"text/html; charset=utf-8","proxyUsed":"basic","cacheState":"hit","cachedAt":"2026-03-29T11:21:07.369Z","creditsUsed":1}},{"url":"https://codesandbox.io/s/schema-validation-compare-zod-superstruct-tqtbx","title":"schema-validation-compare(zod-superstruct) - CodeSandbox","description":"Explore this online schema-validation-compare(zod-superstruct) sandbox and experiment with it yourself using our interactive online playground.","position":5,"markdown":"Installing editor...","metadata":{"language":"en","viewport":"width=device-width, initial-scale=1.0","scrapeId":"019d3953-9958-74c3-8f4c-d9a1b9040776","sourceURL":"https://codesandbox.io/s/schema-validation-compare-zod-superstruct-tqtbx","url":"https://codesandbox.io/p/sandbox/schema-validation-compare-zod-superstruct-tqtbx","statusCode":200,"contentType":"text/html; charset=utf-8","timezone":"America/New_York","proxyUsed":"basic","cacheState":"miss","indexId":"ea7c9f25-abc8-4622-b067-5d3c24c4a659","creditsUsed":1}}]}}