{"success":true,"data":{"web":[{"url":"https://github.com/sinclairzx81/typebox/discussions/614","title":"use tree-shaking to reduce the bundle size by >90% #614 - GitHub","description":"Leverage ESM tree-shaking to decrease bundle sizes by over 90%. For comparison, valibot, which leverages tree-shaking, bundles 703 bytes for the same code.","position":1,"category":"github","markdown":"[Skip to content](https://github.com/sinclairzx81/typebox/discussions/614#start-of-content)\n\nYou signed in with another tab or window. [Reload](https://github.com/sinclairzx81/typebox/discussions/614) to refresh your session.You signed out in another tab or window. [Reload](https://github.com/sinclairzx81/typebox/discussions/614) to refresh your session.You switched accounts on another tab or window. [Reload](https://github.com/sinclairzx81/typebox/discussions/614) to refresh your session.Dismiss alert\n\n{{ message }}\n\n[sinclairzx81](https://github.com/sinclairzx81)/ **[typebox](https://github.com/sinclairzx81/typebox)** Public\n\n- [Notifications](https://github.com/login?return_to=%2Fsinclairzx81%2Ftypebox) You must be signed in to change notification settings\n- [Fork\\\\\n197](https://github.com/login?return_to=%2Fsinclairzx81%2Ftypebox)\n- [Star\\\\\n6.6k](https://github.com/login?return_to=%2Fsinclairzx81%2Ftypebox)\n\n\n# use tree-shaking to reduce the bundle size by >90% \\#614\n\n[samuelstroschein](https://github.com/samuelstroschein)\n\nstarted this conversation in\n[Ideas](https://github.com/sinclairzx81/typebox/discussions/categories/ideas)\n\n[use tree-shaking to reduce the bundle size by >90%](https://github.com/sinclairzx81/typebox/discussions/614#top)#614\n\n[\\\\\nsamuelstroschein](https://github.com/samuelstroschein)\n\non Oct 3, 2023Oct 3, 2023·\n2 comments\n·\n8 replies\n\n\n[Return to top](https://github.com/sinclairzx81/typebox/discussions/614#top)\n\nDiscussion options\n\n# {{title}}\n\nQuote reply\n\nedited\n\n# {{editor}}'s edit\n\n{{actor}} deleted this content\n.\n\n# {{editor}}'s edit\n\n## [\\ samuelstroschein](https://github.com/samuelstroschein) [on Oct 3, 2023Oct 3, 2023](https://github.com/sinclairzx81/typebox/discussions/614\\#discussion-5696394)\n\nOriginal comment in English -\nTranslate to English\n\n| |\n| --- |\n| ## Problem
Typebox ships too large bundle sizes for resource constraint environments. Aka typebox can't be used.
The following code ships 36.3kb \\[ [source](https://bundlejs.com/?q=%40sinclair%2Ftypebox&treeshake=%5B*%5D&text=%22export+type+Settings+%3D+Static%3Ctypeof+Settings%3E%5Cnexport+const+Settings+%3D+Type.Object%28%7B%5Cn%5CtstoragePath%3A+Type.String%28%29%2C%5Cn%7D%29%22&config=%7B%22analysis%22%3Atrue%7D)\\]
```
import { Type, type Static } from \"@sinclair/typebox\"
export type Settings = Static
export const Settings = Type.Object({
\tstoragePath: Type.String(),
})
```
## Proposal
Leverage ESM tree-shaking to decrease bundle sizes by over 90%.
For comparison, [valibot](https://valibot.dev/), which leverages tree-shaking, bundles 703 bytes for the same code \\[ [source](https://bundlejs.com/?q=valibot&treeshake=%5B*%5D&text=%22export+type+Settings+%3D+Output%3Ctypeof+Settings%3E%5Cnexport+const+Settings+%3D+object%28%7B%5Cn%5CtstoragePath%3A+string%28%29%2C%5Cn%7D%29%22&config=%7B%22analysis%22%3Atrue%7D)\\]. A bundle size reduction of 98% compared to typebox.
### Examples
The following code would only import `Object` and `String` validators without all available `Type.*` stuff.
```
import { Object, String, type Static } from \"@sinclair/typebox\"
export type Settings = Static
export const Settings = Object({
\tstoragePath: String(),
})
```
The syntax of `Type.*` could even be sustained with namespace imports which are tree-shaken by bundlers too.
```
import * as Type from \"@sinclair/typebox\"
export type Settings = Static
export const Settings = Type.Object({
\tstoragePath: Type.String(),
})
```
## Additional information
The `Value` import of typebox is too large as well, counting >70kb that are included in the bundle size. Valibot's equivalent `parse` bundles only 100 bytes. |\n\nBetaWas this translation helpful? [Give feedback.](https://github.com/sinclairzx81/typebox/discussions/614#)\n\n1You must be logged in to vote\n\nAll reactions\n\n- 1\n\n## Replies: 2 comments · 8 replies\n\nComment options\n\n# {{title}}\n\nQuote reply\n\n### [\\ sinclairzx81](https://github.com/sinclairzx81) [on Oct 4, 2023Oct 4, 2023](https://github.com/sinclairzx81/typebox/discussions/614\\#discussioncomment-7182464) Maintainer\n\nOriginal comment in English -\nTranslate to English\n\n| [@samuelstroschein](https://github.com/samuelstroschein) Hiya,\n\n* * *\n\n### Bundle Sizes\n\nJust for reference, the following table are the current bundling sizes for various libraries.\n\n| Type System | Minified | GZipped | Reference |\n| --- | --- | --- | --- |\n| TypeBox | 34.3kB | 8.3kB | [0.31.17](https://bundlephobia.com/package/@sinclair/typebox@0.31.17) |\n| Valibot | 35.5kB | 6.6kB | [0.18.0](https://bundlephobia.com/package/valibot@0.18.0) |\n| Zod | 57.0kB | 13.2kB | [3.22.2](https://bundlephobia.com/package/zod@3.22.2) |\n| Ajv | 119.6kB | 35.2kB | [8.12.0](https://bundlephobia.com/package/ajv@8.12.0) |\n| HyperJump | 44.3kB | 11.6kB | [1.6.1](https://bundlephobia.com/package/@hyperjump/json-schema@1.6.1) |\n| ArkType | 67.7kB | 18.9kB | [1.0.21-alpha](https://bundlephobia.com/package/arktype@1.0.21-alpha) |\n\nNote that the TypeBox result above relates specifically to the TypeBuilder (which is currently non-shakable).\n\n* * *\n\n### ESM Modules\n\nThe TypeBox TypeBuilder (everything inside `typebox.ts`) is long overdue for a module split. This module has been prepared for splitting over the past several iterations of the library, but currently pending \"the split\" until things are closer to 1.0.\n\nThe anticipated import scheme post split will be:\n\n```\nimport Type, { Static } from '@sinclair/typebox'\n```\n\nGiven this is a breaking change, there is some reluctance to enact this change until everything is finalized for 1.0 (and that this scheme will be supported into the future). So this is planned for, just not for a while.\n\n### Value Modules\n\n> The Value import of typebox is too large as well, counting >70kb that are included in the bundle size. Valibot's equivalent parse bundles only 100 bytes.\n\nYou won't get to 100 bytes, but you can significantly reduce the size of the Value modules by importing each function individually.\n\n```\nimport { Check } from '@sinclair/typebox/value/check' // > 24 kb\n```\n\nNote: TypeBox does need to import logic to check for all types (as it can't know in advance what types are going to passed to it). Work was done on the 0.30.x and 0.31.x revisions to reduce output size (many code level optimizations), as well as to make each function with it's associated infrastructure individually importable.\n\nOutside of the above, there is very little else that can be done while keeping schematics and validation logic separated (which is a key design principle for the library). However, there may be room to explore more optimal (bundler friendly) Json Schema validation libraries external to TypeBox.\n\nIt would be interesting to see just how minimal a Json Schema implementation could get.\n\nHope this brings some insight\n\nCheers\n\nS |\n\nBetaWas this translation helpful? [Give feedback.](https://github.com/sinclairzx81/typebox/discussions/614#)\n\n2You must be logged in to vote\n\nAll reactions\n\n- 1\n\n6 replies\n\n\nShow 1 previous reply\n\n[](https://github.com/sinclairzx81)\n\nComment options\n\n# {{title}}\n\nQuote reply\n\nedited\n\n# {{editor}}'s edit\n\n{{actor}} deleted this content\n.\n\n# {{editor}}'s edit\n\n#### [sinclairzx81](https://github.com/sinclairzx81) [on Oct 4, 2023Oct 4, 2023](https://github.com/sinclairzx81/typebox/discussions/614\\#discussioncomment-7184623) Maintainer\n\nOriginal comment in English -\nTranslate to English\n\n| |\n| --- |\n| [@samuelstroschein](https://github.com/samuelstroschein) Hiya,
I would expect something like the following (with the default export and type functions would be statically analyzable by bundle optimizers)
```
import Type from 'typebox'
// or ...
import { String, Object } from 'typebox'
```
> The bundle sizes of libraries are irrelevant if tree-shakable. As it stands right now, importing Type leads to 36.3kb that are bundled. I fear that the bundling size with the import schema your propose will make no significant differences as all Type annotations are still bundled.
Keep in mind, individual imports (i.e. as per Valibot) are actually not a big priority for TypeBox, rather the main motivation is to adopt ESM (in whatever capacity) and ensure bundlers have enough to statically analyze (and optimize) the bundle.
In this regard, I feel the `default` export is generally how people would prefer to consume TypeBox under ESM (vs the barrel import) as the default narrows the import scope to only `Type.*`. Additional infrastructure (including the Types themselves) can be imported via `{ ... }` which I would expect a capable bundle optimizer to understand no default import was used (so can be omitted from the output bundle)
This is the reasoning anyway. It could use some testing under popular optimizers. |\n\nBetaWas this translation helpful? [Give feedback.](https://github.com/sinclairzx81/typebox/discussions/614#)\n\nAll reactions\n\n[](https://github.com/samuelstroschein)\n\nComment options\n\n### Uh oh!\n\nThere was an error while loading. [Please reload this page](https://github.com/sinclairzx81/typebox/discussions/614).\n\n# {{title}}\n\nQuote reply\n\n#### [samuelstroschein](https://github.com/samuelstroschein) [on Oct 4, 2023Oct 4, 2023](https://github.com/sinclairzx81/typebox/discussions/614\\#discussioncomment-7184707) Author\n\nOriginal comment in English -\nTranslate to English\n\n| |\n| --- |\n| I am implementing a tree-shakable i18n library. My tests with rollup/vite yielded the following result:
```
// not tree-shakable
import Type from 'typebox'
// tree-shakable
import { String, Object } from 'typebox'
// syntactic sugar of the tree-shakable version is a namespace import
// bundlers ignore the syntactic sugar and treat the following import as
// import { Object } from \"typebox\"
import * as Type from \"typebox\"
Type.Object()
```
Under any circumstance, importing `{ Type }` or `Type` as default import will lead to (too) large bundle sizes. To avoid a breaking change, you can keep `import { Type }` but deprecate `Type`, expose `import { Object, String }` and mention in the docs that a namespace import can be used `import * as Type` for a nicer DX. |\n\nBetaWas this translation helpful? [Give feedback.](https://github.com/sinclairzx81/typebox/discussions/614#)\n\nAll reactions\n\n[](https://github.com/samuelstroschein)\n\nComment options\n\n### Uh oh!\n\nThere was an error while loading. [Please reload this page](https://github.com/sinclairzx81/typebox/discussions/614).\n\n# {{title}}\n\nQuote reply\n\n#### [samuelstroschein](https://github.com/samuelstroschein) [on Oct 4, 2023Oct 4, 2023](https://github.com/sinclairzx81/typebox/discussions/614\\#discussioncomment-7184724) Author\n\nOriginal comment in English -\nTranslate to English\n\n| |\n| --- |\n| I am pressing the issue because typebox is too large for [inlang plugins](https://inlang.com/marketplace) where a plugin has a size of <10kb. Using typebox in its current form would add 36kb to each plugin. A no go. Hence, we had to switch to valibot for plugins. |\n\nBetaWas this translation helpful? [Give feedback.](https://github.com/sinclairzx81/typebox/discussions/614#)\n\nAll reactions\n\n[](https://github.com/sinclairzx81)\n\nComment options\n\n### Uh oh!\n\nThere was an error while loading. [Please reload this page](https://github.com/sinclairzx81/typebox/discussions/614).\n\n# {{title}}\n\nQuote reply\n\n#### [sinclairzx81](https://github.com/sinclairzx81) [on Oct 4, 2023Oct 4, 2023](https://github.com/sinclairzx81/typebox/discussions/614\\#discussioncomment-7185474) Maintainer\n\nOriginal comment in English -\nTranslate to English\n\n| |\n| --- |\n| [@samuelstroschein](https://github.com/samuelstroschein) Heya,
The following would be ok though right?
```
// not tree-shakable
import Type from 'typebox'
// tree-shakable
import { String, Object } from 'typebox'
// presumed also tree-shakable
import * as Type from 'typebox'
```
> I am pressing the issue because typebox is too large for [inlang plugins](https://inlang.com/marketplace) where a plugin has a size of <10kb. Using typebox in its current form would add 36kb to each plugin. A no go. Hence, we had to switch to valibot for plugins.
Inlang looks like a cool project btw. And yeah, that's a bit unfortunate about the plugin size constraints. The TypeBuilder currently gzip's down to around `8kb` with everything in there (assuming you don't need validators). With validators, the minimum you would be looking at around 24kb. Even with TB opting for barrel imports, you're still going to be looking at 20-30kb for validators and additional TB components.
I'm not very keen to deprecate `Type.*` (as I feel this actually improves DX as it narrows specifically to constructible types vs the [other infrastructure](https://github.com/sinclairzx81/typebox/blob/master/src/typebox.ts#L1018-L2828) used for type composition). Explicit imports of types via `{ String, Object }` will most likely be supported via ESM and permit developers to optimize if they need that. I feel this strikes a good balance between something like Zod (not tree shakeable) and Valibot (by being optionally tree shakeable) while still remaining distinctly \"TypeBox\" (as well as not relying too much on the capabilities of JS optimizers)
But let me give it some thought. ESM work is still a fair way off (I have some prototypes I need to test against). Also, I wouldn't expect ESM before the end of the year (but will see how the workload is in December). Just keep in mind that implementing any of this will be significant breaking API change, so do want to have good justification and rationales in place before going ahead with anything. It's a bit of a balancing act (and there are other trade-offs to consider), but should deprecation of `Type.*` be desirable (when contrasted with [other functionality](https://github.com/sinclairzx81/typebox/blob/master/examples/typedef/typedef.ts)), I'll give it a review when I get around to the work.
Let's keep this thread active and open for discussion :) |\n\nBetaWas this translation helpful? [Give feedback.](https://github.com/sinclairzx81/typebox/discussions/614#)\n\nAll reactions\n\n[](https://github.com/samuelstroschein)\n\nComment options\n\n### Uh oh!\n\nThere was an error while loading. [Please reload this page](https://github.com/sinclairzx81/typebox/discussions/614).\n\n# {{title}}\n\nQuote reply\n\nedited\n\n### Uh oh!\n\nThere was an error while loading. [Please reload this page](https://github.com/sinclairzx81/typebox/discussions/614).\n\n# {{editor}}'s edit\n\n{{actor}} deleted this content\n.\n\n# {{editor}}'s edit\n\n#### [samuelstroschein](https://github.com/samuelstroschein) [on Oct 4, 2023Oct 4, 2023](https://github.com/sinclairzx81/typebox/discussions/614\\#discussioncomment-7185573) Author\n\nOriginal comment in English -\nTranslate to English\n\n| |\n| --- |\n| [@sinclairzx81](https://github.com/sinclairzx81)
> The following would be ok though right?
```
// not tree-shakable
import Type from 'typebox'
// tree-shakable
import { String, Object } from 'typebox'
// presumed also tree-shakable
import * as Type from 'typebox'
```
I would remove the default import. It seems to me that you can implement tree-shaking in a non-breaking change manner as follows:
```
// current import schema, still supported
import { Type, Static } from '@sinclair/typebox'
Type.String() // -> warning that `Type` is deprecated in favor of `import * as Type` but it still works!
// new exports of individual types (tree-shakable)
import { String } from '@sinclair/typebox'
String()
// syntactic sugar for type
import * as Type from \"@sinclair/typebox\"
// really a minor \"issue\"/non-issue that static now runs under type.
type X = Type.Static
const X = Type.String()
```
The code above is non-breaking while encouraging best practices and automatic tree-shaking, making typebox substantially better (and hopefully enabling new use cases for typebox in resource constraint environments). No developer would have to debug \"why is typebox shipping 30k+ kb\" if you deprecate the direct import of Type and do not expose a default import. |\n\nBetaWas this translation helpful? [Give feedback.](https://github.com/sinclairzx81/typebox/discussions/614#)\n\nAll reactions\n\nComment options\n\n### Uh oh!\n\nThere was an error while loading. [Please reload this page](https://github.com/sinclairzx81/typebox/discussions/614).\n\n# {{title}}\n\nQuote reply\n\nedited\n\n### Uh oh!\n\nThere was an error while loading. [Please reload this page](https://github.com/sinclairzx81/typebox/discussions/614).\n\n# {{editor}}'s edit\n\n{{actor}} deleted this content\n.\n\n# {{editor}}'s edit\n\n### [\\ samuelstroschein](https://github.com/samuelstroschein) [on May 7, 2025May 7, 2025](https://github.com/sinclairzx81/typebox/discussions/614\\#discussioncomment-13064094) Author\n\nOriginal comment in English -\nTranslate to English\n\n| |\n| --- |\n| Zod released a tree-shakable library [https://v4.zod.dev/packages/mini](https://v4.zod.dev/packages/mini).
They used the pattern I described in [#614 (reply in thread)](https://github.com/sinclairzx81/typebox/discussions/614#discussioncomment-7184707) with `import * as X`. The hesitation to use TypeBox because of the lack of tree-shaking is high. Our use case revolves around plugins that bloat from <10kb to >40kb if TypeBox is used.
A non-breaking implementation could be a sub-path.
```
import * as T from \"@sinclair/typebox/tree-shakable\"
``` |\n\nBetaWas this translation helpful? [Give feedback.](https://github.com/sinclairzx81/typebox/discussions/614#)\n\n1You must be logged in to vote\n\nAll reactions\n\n2 replies\n\n\n[](https://github.com/sinclairzx81)\n\nComment options\n\n### Uh oh!\n\nThere was an error while loading. [Please reload this page](https://github.com/sinclairzx81/typebox/discussions/614).\n\n# {{title}}\n\nQuote reply\n\nedited\n\n### Uh oh!\n\nThere was an error while loading. [Please reload this page](https://github.com/sinclairzx81/typebox/discussions/614).\n\n# {{editor}}'s edit\n\n{{actor}} deleted this content\n.\n\n# {{editor}}'s edit\n\n#### [sinclairzx81](https://github.com/sinclairzx81) [on May 7, 2025May 7, 2025](https://github.com/sinclairzx81/typebox/discussions/614\\#discussioncomment-13065366) Maintainer\n\nOriginal comment in English -\nTranslate to English\n\n| |\n| --- |\n| [@samuelstroschein](https://github.com/samuelstroschein) Hello,
This discussion is quite old (late 2023) and TypeBox has since gone ahead with optimizing the codebase for splitting (early 2024 iirc). According to bundlejs, the following code minifies and gzips to 1.04 kB
```
export const T = Type.Object({
x: Type.Number(),
y: Type.Number(),
z: Type.Number(),
})
// require import here as share link breaks code
import * as Type from \"@sinclair/typebox@0.34.33\"
```
Reference Link (Click on Build)
[https://bundlejs.com/?text=%22export+const+T+%3D+Type.Object%28%7B%5Cn++x%3A+Type.Number%28%29%2C%5Cn++y%3A+Type.Number%28%29%2C%5Cn++z%3A+Type.Number%28%29%2C%5Cn%7D%29%5Cn%5Cn%2F%2F+require+import+here+as+share+link+breaks+code%5Cnimport+\\*+as+Type+from+%5C%22%40sinclair%2Ftypebox%400.34.33%5C%22%22](https://bundlejs.com/?text=%22export+const+T+%3D+Type.Object%28%7B%5Cn++x%3A+Type.Number%28%29%2C%5Cn++y%3A+Type.Number%28%29%2C%5Cn++z%3A+Type.Number%28%29%2C%5Cn%7D%29%5Cn%5Cn%2F%2F+require+import+here+as+share+link+breaks+code%5Cnimport+*+as+Type+from+%5C%22%40sinclair%2Ftypebox%400.34.33%5C%22%22)
Does this solve the issue? |\n\nBetaWas this translation helpful? [Give feedback.](https://github.com/sinclairzx81/typebox/discussions/614#)\n\n1\n\nAll reactions\n\n- 1\n\n[](https://github.com/samuelstroschein)\n\nComment options\n\n### Uh oh!\n\nThere was an error while loading. [Please reload this page](https://github.com/sinclairzx81/typebox/discussions/614).\n\n# {{title}}\n\nQuote reply\n\n#### [samuelstroschein](https://github.com/samuelstroschein) [on May 7, 2025May 7, 2025](https://github.com/sinclairzx81/typebox/discussions/614\\#discussioncomment-13065573) Author\n\nOriginal comment in English -\nTranslate to English\n\n| |\n| --- |\n| Oh yes it does!
I haven't seen the `import * as Type` mentioned in the docs, nor any reference to tree-shaking. Updating the docs would help! |\n\nBetaWas this translation helpful? [Give feedback.](https://github.com/sinclairzx81/typebox/discussions/614#)\n\nAll reactions\n\n[Sign up for free](https://github.com/join?source=comment-repo) **to join this conversation on GitHub**.\nAlready have an account?\n[Sign in to comment](https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fsinclairzx81%2Ftypebox%2Fdiscussions%2F614)\n\nCategory\n\n\n[\\\\\n\\\\\nIdeas](https://github.com/sinclairzx81/typebox/discussions/categories/ideas)\n\nLabels\n\n\nNone yet\n\n\n2 participants\n\n\n[](https://github.com/samuelstroschein)[](https://github.com/sinclairzx81)\n\nHeading\n\nBold\n\nItalic\n\nQuote\n\nCode\n\nLink\n\n* * *\n\nNumbered list\n\nUnordered list\n\nTask list\n\n* * *\n\nAttach files\n\nMention\n\nReference\n\n# Select a reply\n\nLoading\n\n[Create a new saved reply](https://github.com/sinclairzx81/typebox/discussions/614)\n\n👍1 reacted with thumbs up emoji👎1 reacted with thumbs down emoji😄1 reacted with laugh emoji🎉1 reacted with hooray emoji😕1 reacted with confused emoji❤️1 reacted with heart emoji🚀1 reacted with rocket emoji👀1 reacted with eyes emoji\n\nYou can’t perform that action at this time.","metadata":{"ogSiteName":"GitHub","disable-turbo":"false","og:image:width":"1200","turbo-cache-control":"no-preview","user-login":"","visitor-hmac":"84da3255acb6a92f00c73a6135d944d1430534335861e976fc59031495c5397f","fb:app_id":"1401488693436528","octolytics-dimension-repository_is_fork":"false","browser-errors-url":"https://api.github.com/_private/browser/errors","html-safe-nonce":"ff3677cb5f8d8a0061c80bc1852a11edd53623caaf9d58cdd5efb59d91c5b243","octolytics-url":"https://collector.github.com/github/collect","og:image":"https://opengraph.githubassets.com/e77366ed5865195304f950f4d97a0fbe46dc3fd0f8ca6425815568e0f1026c40/sinclairzx81/typebox/discussions/614","expected-hostname":"github.com","og:site_name":"GitHub","og:url":"https://github.com/sinclairzx81/typebox/discussions/614","twitter:site":"@github","ogUrl":"https://github.com/sinclairzx81/typebox/discussions/614","browser-stats-url":"https://api.github.com/_private/browser/stats","theme-color":"#1e2327","title":"use tree-shaking to reduce the bundle size by >90% · sinclairzx81/typebox · Discussion #614 · GitHub","octolytics-dimension-repository_id":"87454905","color-scheme":"light dark","octolytics-dimension-user_id":"3048342","viewport":"width=device-width","github-keyboard-shortcuts":"repository,copilot","twitter:image":"https://opengraph.githubassets.com/e77366ed5865195304f950f4d97a0fbe46dc3fd0f8ca6425815568e0f1026c40/sinclairzx81/typebox/discussions/614","release":"51d2e33e3d1e4839c3ced5f8e35c7a47d3a60f32","octolytics-dimension-user_login":"sinclairzx81","og:image:height":"600","go-import":"github.com/sinclairzx81/typebox git https://github.com/sinclairzx81/typebox.git","visitor-payload":"eyJyZWZlcnJlciI6Imh0dHBzOi8vd3d3Lmdvb2dsZS5jb20vIiwicmVxdWVzdF9pZCI6IjZFNjM6NjVFRjg6NEQzNzA5OjY1RDQ0Mjo2OUM5MEIwQiIsInZpc2l0b3JfaWQiOiIxNDgxMjcxMDY0NjcxMDk1NTYzIiwicmVnaW9uX2VkZ2UiOiJpYWQiLCJyZWdpb25fcmVuZGVyIjoiaWFkIn0=","google-site-verification":"Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I","og:image:alt":"Problem Typebox ships too large bundle sizes for resource constraint environments. Aka typebox can't be used. The following code ships 36.3kb [source] import { Type, type Static } from \"@sinclair/t...","route-action":"discussion_layout","ogDescription":"Problem Typebox ships too large bundle sizes for resource constraint environments. Aka typebox can't be used. The following code ships 36.3kb [source] import { Type, type Static } from \"@sinclair/t...","twitter:description":"Problem Typebox ships too large bundle sizes for resource constraint environments. Aka typebox can't be used. The following code ships 36.3kb [source] import { Type, type Static } from "@s...","octolytics-dimension-repository_network_root_id":"87454905","octolytics-dimension-repository_public":"true","ui-target":"full","hovercard-subject-tag":"discussion:5696394","language":"en","route-controller":"voltron_discussions_fragments","twitter:card":"summary_large_image","og:type":"object","description":"use tree-shaking to reduce the bundle size by >90%","ogTitle":"use tree-shaking to reduce the bundle size by >90% · sinclairzx81/typebox · Discussion #614","octolytics-dimension-repository_nwo":"sinclairzx81/typebox","turbo-body-classes":"logged-out env-production page-responsive","analytics-location":"///voltron/discussions_fragments/discussion_layout","twitter:title":"use tree-shaking to reduce the bundle size by >90% · sinclairzx81/typebox · Discussion #614","route-pattern":"/_view_fragments/Voltron::DiscussionsFragmentsController/show/:user_id/:repository/:discussion_number/discussion_layout(.:format)","octolytics-dimension-repository_network_root_nwo":"sinclairzx81/typebox","hostname":"github.com","apple-itunes-app":"app-id=1477376905, app-argument=https://github.com/_view_fragments/Voltron::DiscussionsFragmentsController/show/sinclairzx81/typebox/614/discussion_layout","og:title":"use tree-shaking to reduce the bundle size by >90% · sinclairzx81/typebox · Discussion #614","og:description":"Problem Typebox ships too large bundle sizes for resource constraint environments. Aka typebox can't be used. The following code ships 36.3kb [source] import { Type, type Static } from \"@sinclair/t...","request-id":"6E63:65EF8:4D3709:65D442:69C90B0B","current-catalog-service-hash":"9f0abe34da433c9b6db74bffa2466494a717b579a96b30a5d252e5090baea7be","fetch-nonce":"v2:214b399d-0b02-a434-c0e2-c95b8977a30f","ogImage":"https://opengraph.githubassets.com/e77366ed5865195304f950f4d97a0fbe46dc3fd0f8ca6425815568e0f1026c40/sinclairzx81/typebox/discussions/614","favicon":"https://github.githubassets.com/favicons/favicon.svg","scrapeId":"019d3953-23d5-7166-b100-398764b9024b","sourceURL":"https://github.com/sinclairzx81/typebox/discussions/614","url":"https://github.com/sinclairzx81/typebox/discussions/614","statusCode":200,"contentType":"text/html; charset=utf-8","timezone":"America/New_York","proxyUsed":"basic","cacheState":"miss","indexId":"f9a22d2d-d4df-42c7-b156-43c02a25059a","creditsUsed":1}},{"url":"https://zenn.dev/m_noto/articles/a2c09f741ba65e?locale=en","title":"A Comparative Evaluation of Valibot and ArkType - Zenn","description":"Valibot achieves the best tree-shaking efficiency thanks to its modular design. Arktype has the smallest node_modules size, but the build size ...","position":2,"markdown":"#### iTranslated by AI\n\nThe content below is an AI-generated translation. This is an experimental feature, and may contain errors. [View original article](https://zenn.dev/m_noto/articles/a2c09f741ba65e)\n\n28\n\n6\n\n[X(Twitter)にポスト](https://twitter.com/intent/tweet?url=https://zenn.dev/m_noto/articles/a2c09f741ba65e&text=Comparing%20Zod%20Alternatives%3A%20A%20Comparative%20Evaluation%20of%20Valibot%20and%20ArkType%EF%BD%9C_mino&hashtags=zenn)[Facebookに投稿](http://www.facebook.com/sharer.php?u=https://zenn.dev/m_noto/articles/a2c09f741ba65e)[はてなブックマークに登録](https://b.hatena.ne.jp/add?mode=confirm&url=https://zenn.dev/m_noto/articles/a2c09f741ba65e&title=Comparing%20Zod%20Alternatives%3A%20A%20Comparative%20Evaluation%20of%20Valibot%20and%20ArkType%EF%BD%9C_mino)\n\n[テーマ「フリーテーマ」](https://zenn.dev/contests/zennfes2025free)\n\n[\\\\\n\\\\\nzod](https://zenn.dev/topics/zod) [\\\\\n\\\\\nValibot](https://zenn.dev/topics/valibot) [\\\\\n\\\\\narktype](https://zenn.dev/topics/arktype) [\\\\\n\\\\\nzennfes2025free](https://zenn.dev/topics/zennfes2025free) [\\\\\n\\\\\ntech](https://zenn.dev/tech-or-idea)\n\nNice to meet you, I'm [\\_mino](https://x.com/nt_mino)!\n\nIn this article, I've summarized the results of comparing and verifying several trending libraries to see if Zod is truly the best fit for validation in frontend development, or if there might be other more suitable validation libraries.\n\nIf you are struggling to choose a validation library, I hope you find this helpful.\n\nFor those wondering \"What is validation?\", this explanation is easy to understand!\n\n[https://wa3.i-3-i.info/word11610.html](https://wa3.i-3-i.info/word11610.html)\n\n## **🚀 Target** Libraries\n\n### Zod / v4\n\nThe most popular TypeScript-first schema validation library. It automatically generates types from schemas to ensure data safety.\n\n**Features and Characteristics:**\n\n- Intuitive syntax using method chaining (`z.string().email().min(5)`)\n- Error handling without try-catch via `.safeParse()`\n- Extensive schema manipulation (extension, selection, transformation, etc.)\n- Type conversion features (e.g., automatic string-to-number conversion)\n- Extensive ecosystem\n\n[https://zod.dev/](https://zod.dev/)\n\n### Valibot / v1\n\nA next-generation validation library that achieves over 90% bundle size reduction through modular design. Developed as a lightweight alternative to Zod.\n\n**Features and Characteristics:**\n\n- Pipeline syntax (verifies in order, e.g., string → email format with `v.pipe(v.string(), v.email())`)\n- Lightweight design where only the features used are bundled\n- Modular structure combining small functions\n- Fast validation processing and compilation\n- Optimization for mobile and Edge environments\n\n[**https://valibot.dev/** \\\\\n\\\\\nvalibot.dev](https://valibot.dev/)\n\n[https://valibot.dev/](https://valibot.dev/)\n\n### ArkType / v2\n\nAn innovative string-based validation library that is closest to TypeScript syntax. Characterized by automatic optimization through a built-in type system.\n\n**Features and Characteristics:**\n\n- TypeScript-like shorthand syntax (`'string>=2'` for \"a string of 2 or more characters\")\n- Internal optimization for union type resolution\n- Pre-detection of type contradictions (e.g., both number and string)\n- Real-time error display in the editor\n- Fast runtime validation (ideal for high-volume, high-frequency processing)\n\n[https://arktype.io/](https://arktype.io/)\n\n## **📚 Trends and Popularity**\n\nHere is the Star History chart (GitHub star history).\n\n\n\n**Zod**'s momentum remains unabated, and its popularity is overwhelming compared to other validation libraries. With the significant improvement in developer experience due to the v4 upgrade, I believe its popularity will accelerate even further.\n\nOn the other hand, **Valibot** and **ArkType** are also steadily gaining popularity and have become noteworthy contenders.\n\nSince both libraries receive continuous updates and their ecosystems are gradually becoming more active, they have the potential to become strong competitors to Zod in the future.\n\n## 📊 Comparison and Benchmarks\n\nI conducted a comparison and verification of each library under the following measurement conditions.\n\n**Measurement Environment**\n\n- Next.js 15.5.4\n- Node.js v20.10.0\n- TypeScript 5.x\n- Measurement tool: performance.now()\n\n**Measurement Units**\n\n- **μs (microseconds)**: One millionth of a second (0.000001 seconds)\n- **ops/s**: Operations per second\n- **ms (milliseconds)**: One thousandth of a second (0.001 seconds)\n\n### Execution Speed Comparison\n\n**Simple Schema - Valid Data**\n\n| Library | Average Execution Time | Processing Speed | Relative Performance |\n| --- | --- | --- | --- |\n| **Arktype** | 0.775 μs | 1,281,600 ops/s | 1.00x (Baseline) |\n| **Zod** | 0.927 μs | 1,066,714 ops/s | 1.20x slower |\n| **Valibot** | 0.943 μs | 1,030,532 ops/s | 1.24x slower |\n\n- Measured with correct data that satisfies all validation rules.\n\n**Simple Schema - Invalid Data**\n\n| Library | Average Execution Time | Processing Speed | Relative Performance |\n| --- | --- | --- | --- |\n| **Arktype** | 0.518 μs | 1,930,050 ops/s | 1.00x (Baseline) |\n| **Valibot** | 3.599 μs | 278,022 ops/s | 6.94x slower |\n| **Zod** | 20.620 μs | 48,931 ops/s | 39.46x slower |\n\n- Measured with invalid data that causes validation errors (e.g., insufficient characters, invalid email format).\n\n**Complex Schema**\n\n| Library | Average Execution Time | Processing Speed | Relative Performance |\n| --- | --- | --- | --- |\n| **Arktype** | 0.003 ms | 378,972 ops/s | 1.00x (Baseline) |\n| **Zod** | 0.059 ms | 17,271 ops/s | Approx. 21.94x slower |\n| **Valibot** | 0.105 ms | 9,593 ops/s | Approx. 39.50x slower |\n\n- Measured with large-scale data containing nested objects and arrays.\n\n### Bundle Size Comparison\n\n**Production Build Size (Actual Next.js values)**\n\n| Library | Page Size | First Load JS | node\\_modules | Tree-shaking Efficiency |\n| --- | --- | --- | --- | --- |\n| **Valibot** | 1.35 KB | 127 KB | 1.7 MB | ◎ |\n| **Zod** | 1.30 KB | 171 KB | 5.6 MB | ◎ |\n| **Arktype** | 1.58 KB | 162 KB | 628 KB | ⚪︎ |\n\n**Notes**\n\n- Valibot achieves the best tree-shaking efficiency thanks to its modular design.\n- Arktype has the smallest node\\_modules size, but the build size is medium because it includes a JIT compiler.\n- Zod has the largest bundle size due to its rich set of features.\n\n### Initialization Performance\n\n| Library | Schema Creation Time | First Execution | Subsequent Executions | JIT Compilation |\n| --- | --- | --- | --- | --- |\n| **Valibot** | 0.014 ms | 0.119 ms | 0.012 ms | None |\n| **Arktype** | 0.121 ms | 0.666 ms | 0.010 ms | Yes (66x faster) |\n| **Zod** | 0.243 ms | 0.516 ms | 0.014 ms | Yes (36x faster) |\n\n**Notes**\n\n- Arktype is fast from the first run (JIT optimized).\n- Zod has significantly improved with the introduction of JIT in v4.\n- Valibot has an excellent TTI (Time to Interactive) due to its initialization-focused design.\n\n### Other Comparison Items\n\n| Item | Zod | Valibot | ArkType |\n| --- | --- | --- | --- |\n| **Execution Speed (Valid Data)** | ⚪︎ Standard | ⚪︎ Standard | ◎ Fast |\n| **Execution Speed (Invalid Data)** | △ Slow | ⚪︎ Standard | ◎ Fast |\n| **Execution Speed (Complex Schema)** | ⚪︎ Standard | △ Slow | ◎ Fast |\n| **Bundle Size** | △ Large | ◎ Smallest | ⚪︎ Medium |\n| **Next.js Integration** | ◎ Excellent | ⚪︎ Good | ⚪︎ Good |\n| **Error Messages** | ◎ Detailed | ⚪︎ Good | ⚪︎ Good |\n| **Custom Validation** | ◎ Flexible | ◎ Flexible | ⚪︎ Limited |\n| **Asynchronous Validation** | ◎ Supported | ◎ Supported | △ Not supported (External implementation required) |\n| **Server-side Usage** | ◎ Fully supported (Node.js optimized) | ◎ Fully supported (Lightweight design) | ⚪︎ Supported (Some limitations) |\n| **Type Inference Performance** | ⚪︎ Standard (Heavy when complex) | ◎ Fast (Efficient) | ◎ Fastest (String parsing) |\n| **Edge Runtime** | ◎ Supported (Stable operation) | ◎ Supported (Optimized) | ⚪︎ Partially supported (Verification required) |\n\n## 🧑💻 Comparison of Implementation Methods\n\nUsing a \"Corporate Inquiry Form\" as an example, we will compare the implementation methods using each validation library.\n\nThe following five items are required as the common data structure for input data:\n\n```\n// Structure of the inquiry form used commonly across each library\ninterface ContactForm {\n company: string; // Company Name (Required)\n name: string; // Name (Required)\n email: string; // Email Address (Required, email format)\n category: 'design' | 'engineering' | 'sales' | 'marketing'; // Category (Required, selection)\n message: string; // Message (Required)\n}\n```\n\n\n\n### Zod\n\n**Schema Definition**\n\n```\nimport { z } from \"zod\"\n\n// Define validation rules using the method chaining approach\nconst contactSchema = z.object({\n company: z.string()\n .min(1, \"Please enter the company name\")\n .max(100, \"Company name must be within 100 characters\"),\n name: z.string()\n .min(1, \"Please enter your name\")\n .max(50, \"Name must be within 50 characters\"),\n email: z.string()\n .min(1, \"Please enter your email address\")\n .email(\"Please enter a valid email address\"),\n category: z.enum([\"design\", \"engineering\", \"sales\", \"marketing\"], {\n message: \"Please select a category\",\n }),\n message: z.string()\n .min(1, \"Please enter your inquiry\")\n .max(1000, \"Inquiry must be within 1000 characters\"),\n})\n\n// Type Inference\ntype ContactForm = z.infer\n```\n\n\n\n**Validation Execution**\n\n```\nconst handleSubmit = async (data: ContactForm) => {\n const result = contactSchema.safeParse(data)\n\n if (result.success) {\n // On success: result.data contains validated data\n console.log(\"Validated Data:\", result.data)\n } else {\n // On failure: result.error.issues contains error info\n const fieldErrors: Record = {}\n result.error.issues.forEach((issue) => {\n const fieldName = issue.path[0] as string\n if (fieldName && !fieldErrors[fieldName]) {\n fieldErrors[fieldName] = issue.message\n }\n })\n // Error display processing\n }\n}\n```\n\n\n\n### Valibot\n\n**Schema Definition**\n\n```\nimport * as v from \"valibot\"\n\n// Combine validations using the pipeline approach\nconst contactSchema = v.object({\n company: v.pipe(\n v.string(),\n v.minLength(1, \"Please enter at least 1 character for the company name\"),\n v.maxLength(100, \"Company name must be within 100 characters\")\n ),\n name: v.pipe(\n v.string(),\n v.minLength(1, \"Please enter at least 1 character for the name\"),\n v.maxLength(50, \"Name must be within 50 characters\")\n ),\n email: v.pipe(\n v.string(),\n v.minLength(1, \"Please enter at least 1 character for the email address\"),\n v.email(\"Please enter a valid email address\")\n ),\n category: v.picklist([\"design\", \"engineering\", \"sales\", \"marketing\"]),\n message: v.pipe(\n v.string(),\n v.minLength(1, \"Please enter at least 1 character for your inquiry\"),\n v.maxLength(1000, \"Inquiry must be within 1000 characters\")\n ),\n})\n\n// Type Inference\ntype ContactForm = v.InferOutput\n```\n\n\n\n**Validation Execution**\n\n```\nconst handleSubmit = async (data: ContactForm) => {\n // Execute validation with safeParse\n const result = v.safeParse(contactSchema, data)\n\n if (result.success) {\n // On success: result.output contains validated data\n console.log(\"Validated Data:\", result.output)\n } else {\n // On failure: result.issues contains error info\n const fieldErrors: Record = {}\n result.issues.forEach((issue) => {\n const fieldName = issue.path?.[0]?.key as string\n if (fieldName && !fieldErrors[fieldName]) {\n fieldErrors[fieldName] = issue.message\n }\n })\n // Error display processing\n }\n}\n```\n\n\n\n### ArkType\n\n**Schema Definition**\n\n```\nimport { type } from \"arktype\"\n\n// TypeScript-like type literal syntax\nconst contactSchema = type({\n company: \"1<=string<=100\",\n name: \"1<=string<=50\",\n email: \"string\",\n category: \"'design'|'engineering'|'sales'|'marketing'\",\n message: \"1<=string<=1000\"\n})\n\n// Type Inference\ntype ContactForm = typeof contactBaseSchema.infer\n\n// Detailed validation implemented in a separate function\nfunction validateContact(data: ContactForm): { valid: boolean; errors: Record } {\n const errors: Record = {}\n\n if (data.company.length === 0) {\n errors.company = \"Please enter the company name\"\n } else if (data.company.length > 100) {\n errors.company = \"Company name must be within 100 characters\"\n }\n\n if (data.name.length === 0) {\n errors.name = \"Please enter your name\"\n } else if (data.name.length > 50) {\n errors.name = \"Name must be within 50 characters\"\n }\n\n if (data.email.length === 0) {\n errors.email = \"Please enter your email address\"\n } else {\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n if (!emailRegex.test(data.email)) {\n errors.email = \"Please enter a valid email address\"\n }\n }\n\n if (data.message.length === 0) {\n errors.message = \"Please enter your inquiry\"\n } else if (data.message.length < 10) {\n errors.message = \"Inquiry must be at least 10 characters long\"\n } else if (data.message.length > 1000) {\n errors.message = \"Inquiry must be within 1000 characters\"\n }\n\n return {\n valid: Object.keys(errors).length === 0,\n errors,\n }\n}\n```\n\n\n\n**Validation Execution**\n\n```\nconst handleSubmit = async (data: ContactForm) => {\n // Step 1: Type check\n const typeCheckResult = contactBaseSchema(data)\n\n // Determine by checking the \"problems\" property\n if (\"problems\" in typeCheckResult) {\n // Handle type errors\n const fieldErrors: Record = {}\n (typeCheckResult as any).problems.forEach((problem: any) => {\n const pathKey = problem.path?.[0]\n if (pathKey && !fieldErrors[pathKey]) {\n fieldErrors[pathKey] = \"Input type is invalid\"\n }\n })\n // Error display processing\n } else {\n // Step 2: Custom validation\n const validData = typeCheckResult as ContactForm\n const validation = validateContact(validData)\n\n if (validation.valid) {\n console.log(\"Validated Data:\", validData)\n } else {\n // Handle validation errors\n setErrors(validation.errors)\n }\n }\n}\n```\n\n\n\n### Summary\n\nZod and Valibot are characterized by their **intuitive and simple syntax** using method chaining or pipeline approaches. Validation rules can be understood at a glance, and since error handling is unified with `safeParse`, they offer **excellent code readability and maintainability, making them well-suited for team development**.\n\nArkType takes a unique approach by adopting a **TypeScript-like type literal syntax**. While basic type checks can be written concisely, implementing detailed validation or customizing error messages requires separate custom function implementations. As a result, the **amount of implementation code tends to increase, and the unique syntax may lead to a higher learning curve**.\n\n## 📌 Personal Impressions\n\nWith the release of Zod v4, the previous issues regarding performance and bundle size have been significantly improved, and it is likely to **continue being a strong candidate for validation libraries**.\n\nFurthermore, its ecosystem and community are overwhelmingly active compared to other libraries, and Zod seems to have the upper hand if you value maturity.\n\nHowever, if you prioritize performance above all else or are building a simple application, **choosing a library specialized for specific strengths** like Valibot or ArkType might be more appropriate.\n\nI actually tried introducing Valibot into a personal project, and I didn't encounter any particular problems or unsupported cases. I feel it is a solid candidate to consider for medium-sized applications.\n\n## 👀 Closing\n\nThank you for reading to the end! ☺️\n\nI hope this article helps you in your development, even if only a little!\n\nI also share my learnings and insights on tech selection and in-depth analysis of the latest technologies on my personal blog. If you are interested, I would be happy if you could check it out here!\n\n[https://techbuild.app/blog](https://techbuild.app/blog)\n\n### Discussion\n\n\n\nログインするとコメントできます\n\nLogin","metadata":{"zenn:image":"https://storage.googleapis.com/zenn-user-upload/avatar/c4e5376326.jpeg","ogTitle":"Comparing Zod Alternatives: A Comparative Evaluation of Valibot and ArkType","ogSiteName":"Zenn","viewport":["width=device-width, initial-scale=1","width=device-width","width=device-width","width=device-width","width=device-width","width=device-width"],"language":"en","title":"Comparing Zod Alternatives: A Comparative Evaluation of Valibot and ArkType","ogImage":"https://res.cloudinary.com/zenn/image/upload/s--R5mcJRdl--/c_fit%2Cg_north_west%2Cl_text:notosansjp-medium.otf_55:Comparing%2520Zod%2520Alternatives%253A%2520A%2520Comparative%2520Evaluation%2520of%2520Valibot%2520and%2520ArkType%2Cw_1010%2Cx_90%2Cy_100/g_south_west%2Cl_text:notosansjp-medium.otf_37:_mino%2Cx_203%2Cy_121/g_south_west%2Ch_90%2Cl_fetch:aHR0cHM6Ly9zdG9yYWdlLmdvb2dsZWFwaXMuY29tL3plbm4tdXNlci11cGxvYWQvYXZhdGFyL2M0ZTUzNzYzMjYuanBlZw==%2Cr_max%2Cw_90%2Cx_87%2Cy_95/v1627283836/default/og-base-w1200-v2.png?_a=BACAGSGT","og:title":"Comparing Zod Alternatives: A Comparative Evaluation of Valibot and ArkType","og:type":"article","og:site_name":"Zenn","og:url":"https://zenn.dev/m_noto/articles/a2c09f741ba65e?locale=en","twitter:card":"summary_large_image","og:image":"https://res.cloudinary.com/zenn/image/upload/s--R5mcJRdl--/c_fit%2Cg_north_west%2Cl_text:notosansjp-medium.otf_55:Comparing%2520Zod%2520Alternatives%253A%2520A%2520Comparative%2520Evaluation%2520of%2520Valibot%2520and%2520ArkType%2Cw_1010%2Cx_90%2Cy_100/g_south_west%2Cl_text:notosansjp-medium.otf_37:_mino%2Cx_203%2Cy_121/g_south_west%2Ch_90%2Cl_fetch:aHR0cHM6Ly9zdG9yYWdlLmdvb2dsZWFwaXMuY29tL3plbm4tdXNlci11cGxvYWQvYXZhdGFyL2M0ZTUzNzYzMjYuanBlZw==%2Cr_max%2Cw_90%2Cx_87%2Cy_95/v1627283836/default/og-base-w1200-v2.png?_a=BACAGSGT","next-head-count":["2","2","2","2","2"],"ogUrl":"https://zenn.dev/m_noto/articles/a2c09f741ba65e?locale=en","apple-mobile-web-app-title":"Zenn","zenn:description":"Article by _mino","favicon":"https://static.zenn.studio/images/logo-transparent.png","scrapeId":"019d3953-23d5-7166-b100-3c44213307e0","sourceURL":"https://zenn.dev/m_noto/articles/a2c09f741ba65e?locale=en","url":"https://zenn.dev/m_noto/articles/a2c09f741ba65e?locale=en","statusCode":200,"contentType":"text/html; charset=utf-8","proxyUsed":"basic","cacheState":"hit","cachedAt":"2026-03-29T11:20:40.368Z","creditsUsed":1}},{"url":"https://valibot.dev/","title":"Valibot: The modular and type safe schema library","description":"The biggest difference is the modular design of our API and the ability to reduce the bundle size to a minimum through tree shaking and code splitting.","position":3,"markdown":"# Validate unknowndata with confidence\n\nValibot is the open source schema library for TypeScript with bundle size, type safety and developer experience in mind.\n\n[Get started](https://valibot.dev/guides/introduction/) [Playground](https://valibot.dev/playground/)\n\n\n\n## Highlights you should not miss\n\n- 🔒\n\n\n\n ### Fully type safe\n\n\n\n Enjoy the benefits of type safety and static type inference in TypeScript\n\n- 📦\n\n\n\n ### Small bundle size\n\n\n\n Due to the modular design of our API the bundle size starts at less than 700 bytes\n\n- 🚧\n\n\n\n ### Validate everything\n\n\n\n Supports almost any TypeScript type from primitive values to complex objects\n\n- 🛟\n\n\n\n ### 100% test coverage\n\n\n\n Valibot's source code is open source and fully tested with 100% coverage\n\n- 🔋\n\n\n\n ### Helpers included\n\n\n\n Important validation and transformation helpers are already included\n\n- 🧑💻\n\n\n\n ### API with great DX\n\n\n\n Minimal, readable and well thought out API for a great developer experience\n\n\n## Frequently asked questions\n\n- Where can I enter my credit card?\n\n\n You don't have to! Valibot is available free of charge and licensed under the [MIT License](https://github.com/open-circle/valibot/blob/main/LICENSE.md). However, we rely on partners and sponsors to fund the project. If your company would like to support us, you can take a look at our sponsor page on [GitHub](https://github.com/sponsors/fabian-hiller).\n\n- What exactly does Valibot do?\n\n\n The core function of Valibot is to create a schema that describes a structured data set. A schema can be compared to a type definition in TypeScript. The big difference is that TypeScript types are \"not executed\" and are more or less a DX feature. A schema on the other hand, apart from the inferred type definition, can also be executed at runtime to guarantee type safety of unknown data.\n\n- How does a modular design reduce bundle size?\n\n\n Due to the modular design of our API, a bundler can use the import statements to remove the code you don't need. This way, only the code that is actually used ends up in your production build. This also allows us to add new functionality to Valibot without increasing the size for all users.\n\n- How is it different from Zod?\n\n\n The functionality of Valibot is very similar to Zod. The biggest difference is the modular design of our API and the ability to reduce the bundle size to a minimum through tree shaking and code splitting. Depending on the schema, Valibot can reduce the bundle size up to 95% compared to Zod. Especially for client-side validation of forms and serverless environments this can be a big advantage.\n\n\n[Get started](https://valibot.dev/guides/introduction/) [Playground](https://valibot.dev/playground/)","metadata":{"og:title":"Valibot: The modular and type safe schema library","theme-color":"#111827","og:image":"https://valibot.dev/og-image","og:type":"website","og:description":"Validate unknown data with Valibot, the open source schema library with bundle size, type safety and developer experience in mind.","og:url":"https://valibot.dev/","description":"Validate unknown data with Valibot, the open source schema library with bundle size, type safety and developer experience in mind.","language":"en","ogTitle":"Valibot: The modular and type safe schema library","ogDescription":"Validate unknown data with Valibot, the open source schema library with bundle size, type safety and developer experience in mind.","viewport":"width=device-width, initial-scale=1.0","title":"Valibot: The modular and type safe schema library","twitter:card":"summary_large_image","ogUrl":"https://valibot.dev/","ogImage":"https://valibot.dev/og-image","favicon":"https://valibot.dev/icon-32px.png","scrapeId":"019d3953-23d5-7166-b100-43d35d19bee2","sourceURL":"https://valibot.dev/","url":"https://valibot.dev/","statusCode":200,"contentType":"text/html; charset=utf-8","proxyUsed":"basic","cacheState":"hit","cachedAt":"2026-03-28T21:20:01.561Z","creditsUsed":1}},{"url":"https://www.thoughtworks.com/en-us/radar/languages-and-frameworks/valibot","title":"Valibot | Technology Radar | Thoughtworks United States","description":"This architecture allows bundlers to perform effective tree shaking and code splitting, including only the validation functions actually used.","position":4,"markdown":"[Technology Radar](https://www.thoughtworks.com/en-us/radar)\n\n[Download](https://www.thoughtworks.com/en-us/radar/languages-and-frameworks/valibot#download)\n\n\n\n\n\n\n\n\n\n# Valibot\n\n[Languages & FrameworksBack](https://www.thoughtworks.com/en-us/radar/languages-and-frameworks)\n\n- [Search](https://www.thoughtworks.com/en-us/radar/search)\n- [Techniques](https://www.thoughtworks.com/en-us/radar/techniques)\n- [Platforms](https://www.thoughtworks.com/en-us/radar/platforms)\n- [Tools](https://www.thoughtworks.com/en-us/radar/tools)\n- [Languages & Frameworks](https://www.thoughtworks.com/en-us/radar/languages-and-frameworks)\n\n\n\nClose\n\nPublished : Nov 05, 2025\n\nNov 2025\n\nAssess?Worth exploring with the goal of understanding how it will affect your enterprise.\n\n**[Valibot](https://valibot.dev/)** is a schema validation library in TypeScript. Like other popular TypeScript validation libraries such as [Zod](https://zod.dev/) and [Ajv](https://www.thoughtworks.com/en-us/radar/languages-and-frameworks/ajv), it provides type inference, but its modular design sets it apart. This architecture allows bundlers to perform effective tree shaking and code splitting, including only the validation functions actually used. Valibot can reduce the bundle size by up to 95% compared to Zod in optimal scenarios. It’s an appealing choice for schema validation in environments where bundle size is critical, such as client-side validation or serverless functions.\n\nRelated blips\n\n- [Ajv\\\\\n\\\\\nTrial\\\\\n\\\\\nLanguages & Frameworks\\\\\n\\\\\nSeptember 2023](https://www.thoughtworks.com/en-us/radar/languages-and-frameworks/ajv)\n\n\n\n### Download the PDF\n\n[English](https://www.thoughtworks.com/content/dam/thoughtworks/documents/radar/2025/11/tr_technology_radar_vol_33_en.pdf) \\| [Español](https://www.thoughtworks.com/content/dam/thoughtworks/documents/radar/2025/11/tr_technology_radar_vol_33_es.pdf) \\| [Português](https://www.thoughtworks.com/content/dam/thoughtworks/documents/radar/2025/11/tr_technology_radar_vol_33_pt.pdf) \\| [中文](https://www.thoughtworks.com/content/dam/thoughtworks/documents/radar/2025/11/tr_technology_radar_vol_33_cn.pdf)\n\n\n\n### Sign up for the Technology Radar newsletter\n\n[Subscribe now](https://www.thoughtworks.com/radar#subscribe)\n\n## Visit our archive to read previous volumes\n\n[Go to archive](https://www.thoughtworks.com/en-us/radar/archive)","metadata":{"ogDescription":"Valibot is a schema validation library in TypeScript. Like other popular TypeScript validation libraries such as Zod and Ajv, it provides type inference, but its [...]","og:url":"https://www.thoughtworks.com/en-us/radar/languages-and-frameworks/valibot","twitter:image:src":"https://www.thoughtworks.com/en-us/radar/languages-and-frameworks/valibot/meta.jpeg","language":"en-US","og:title":"Valibot | Technology Radar | Thoughtworks United States","ogUrl":"https://www.thoughtworks.com/en-us/radar/languages-and-frameworks/valibot","template":"radar-page","name":"Valibot | Technology Radar | Thoughtworks United States","robots":"index,follow","twitter:card":"summary_large_image","twitter:account_id":"23009949","description":"Valibot is a schema validation library in TypeScript. Like other popular TypeScript validation libraries such as Zod and Ajv, it provides type inference, but its [...], Valibot is a schema validation library in TypeScript. Like other popular TypeScript validation libraries such as Zod and Ajv, it provides type inference, but its [...]","ogTitle":"Valibot | Technology Radar | Thoughtworks United States","viewport":"width=device-width, initial-scale=1","tw_country_locale":"en-us","og:description":"Valibot is a schema validation library in TypeScript. Like other popular TypeScript validation libraries such as Zod and Ajv, it provides type inference, but its [...]","ogSiteName":"Thoughtworks","shareaholic:site_id":"6b2351f5b26249ba68dff4ebf816c023","google-site-verification":["AA43W6MsN2rMNjvAWJThG_C2DdiFIbwn2xf0J8Vd2eE","kiO_CiGIcZKuyAwkoZIXjBOUAWRv57hnbTDbaHyvrV0"],"twitter:title":"Valibot | Technology Radar | Thoughtworks United States","fb:app_id":"[117154494974817]","tw_content_type":"Radar","image":"https://www.thoughtworks.com/en-us/radar/languages-and-frameworks/valibot/meta.jpeg","ogImage":"https://www.thoughtworks.com/en-us/radar/languages-and-frameworks/valibot/meta.jpeg","og:image":"https://www.thoughtworks.com/en-us/radar/languages-and-frameworks/valibot/meta.jpeg","twitter:description":"Valibot is a schema validation library in TypeScript. Like other popular TypeScript validation libraries such as Zod and Ajv, it provides type inference, but its [...]","og:site_name":"Thoughtworks","title":" Valibot | Technology Radar | Thoughtworks United States","favicon":"https://www.thoughtworks.com/etc.clientlibs/thoughtworks/clientlibs/clientlib-site/resources/images/favicon.ico","scrapeId":"019d3953-23d5-7166-b100-472c64d8fbd3","sourceURL":"https://www.thoughtworks.com/en-us/radar/languages-and-frameworks/valibot","url":"https://www.thoughtworks.com/en-us/radar/languages-and-frameworks/valibot","statusCode":200,"contentType":"text/html;charset=utf-8","timezone":"America/New_York","proxyUsed":"basic","cacheState":"miss","indexId":"2a01dffb-ccee-4a4e-b781-04b3e69966fd","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":"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.","position":5,"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\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":{"viewport":"width=device-width, initial-scale=1","ogSiteName":"Devmystify","twitter:image":"https://d3tgxfx23qkrig.cloudfront.net/uploads/media/171/wide_thumb-top-6-validation-libraries-for-javascript-in-2025.png","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.","twitter:title":"Top 6 Validation libraries for JavaScript in 2025 | Devmystify","next-size-adjust":"","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.","twitter:card":"summary_large_image","twitter:creator":"@Devmystify","og:type":"website","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","og: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","og:image:height":"630","title":"Top 6 Validation libraries for JavaScript in 2025 | Devmystify","og:site_name":"Devmystify","language":"en","og:locale":"en_US","sentry-trace":"b287d3a35797d1ca7187a929aca2ff15-1724b50b48cb2604-1","og:url":"https://devmystify.com/blog/top-6-validation-libraries-for-javascript-in-2025","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","favicon":"https://devmystify.com/favicon.ico","scrapeId":"019d3953-23d5-7166-b100-4b91c5c75f98","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","timezone":"America/New_York","proxyUsed":"basic","cacheState":"miss","indexId":"ae727759-408f-4a62-a0bb-0798acd681dc","creditsUsed":1}}]}}