It’s worth noting that tree-shaking isn’t always available. It requires a build step. However, valibot is structured so that you can still only import what you actually need by using multiple direct imports, which is nice of them.
The problem with zod treeshaking IS NOT import * as z! I’ve seen bundlers remove unreachable things from namespace imports (unless you are doing dynamic lookups). The problem is that everything is attached to the prototype. If you import one validator, you have to import every other one (since all of the properties like .optional have to be present) This is exactly the reason why I’m excited for the pipeline operator. Should bring analizability of pure functions, and dx convenience of method chaining together. Wonder how this is going to impact library design, and if we are to see the move away from putting things onto the prototype just to get method chaining working.
A problem with most JS/TS validation libraries, except Zod, is that it's not possible to introspect the validation schema. So you're getting locked into the library-specific schema with no way of determining properties at runtime, which is essential in form validation libraries to generate default values for type safety, web browser constraints, etc. Without a validation standard it's hard to do anything about this, and it's easy to overlook when just looking at speed and size.
Try TypeBox, it does everything Zod does, but is based on the JSON schema standard (and to reflect you reflect on that schema) It's as close to a standard type schema as exists.
@@BinaryReader TypeBox works as well, but as you say it's close to a standard, not an accepted standard. Which is the real problem - but even if it was, it's not that much fun to build a library if you have to adhere to a dry specification. I guess that's why we have a dozen libraries, doing the same thing (as projects like typeschema shows when unifying most of them on the validation level), competing for microseconds (that's more fun), ignoring things like DSL lock-in and lack of introspection. Otherwise, why this fragmentation for something as fundamental as type validation? Didn't we learn anything from the browser wars?
@@andreas.soderlund TBH, the lack of "standards" is a problem that will probably never go away in the JS/TS ecosystem, simply because the languages that have standards, by contrast, were "sponsored" by a company from the beginning.
For server side applications, runtime memory allocation is much more important than bundle size. This is where libraries like typia, ts-runtime-checks excel. They generate validation and error handling code at compile time.
Very generally, memory allocation is also very related to speed as allocating memory on the heap and then garbage collecting it is very cpu expensive. For frontend though, the bundle size is arguably more important than speed.
The problem with typia is you need to take on a lot of non-standard compiler plugins to make it work. It doesn't integrate at all with watch reload tooling, doesnt work in Deno (not least without adding extreme compiler delay (there's a reason people use swc)), and the code and schemas it emits are utterly archaic (I can't even use the schemas as they're structured so poorly we tried using it for Swagger generation...just nope). Using it also locks you into the tool and associated poor workflows for the long term.....pass. Can't recommend it, had some wins early but turned into a footgun and ditched it for TypeBox. Havent used ts-runtime-checks, but looks like it does the same thing...so pass again. Need proper TS tools from Microsoft to solve compiler emitted types really...and they need to integrate with swc and esbuild and be fast.
Rewriting a library that is 13.1 kilobytes in size to reduce bundle by 10-12kb, really? Isn't it going a little bit too far? Also, IMO, very questionable naming of functions such as 'email', 'object', 'string'. I don't think it's too uncommon to have a 'const email = '...';' somewhere in your code, so you'll end up either renaming that or the imported function. While 'z.email()' doesn't conflict with existing variables and also is immediately obvious to readers of the code.
Your second point is my concern, too. Hard to bring this into an existing library without rewriting a lot of your variables or having to ‘import as’ with some custom names.
Would I be wrong if I said: large projects would use most of Zod's imports and the tree shaking, after all, won't matter that much, and similarly for small projects, their overall performance won't mind an additional 8kb anyways. Overall, in most cases, people would prefer mature projects over a tiny bit "better" ones. Maybe that's why ZOD didn't care that much about starting with an obviously slightly better design. Or they were leaving room for competition??
People add 41kB framer-motion for fade-ins or react-hook-forms (even worse, formik) for a single form, and here we are fat-shaming zod for being 13kB but being the absolute goat
just tested it and you can indeed also import from zod like this. Made a quick dummy schema with import { object, string } from "zod"; and it worked perfectly fine. Ofc the import cost is a bit higher because it includes stuff like refine, transform and parse in the import, but that's honestly fine? I accidentally do this a TON when vscode doesn't seem to understand that I'm trying to write a generic type or converting a type alias to an interface (or viceversa) and it autoimports stuff like number or string from zod.
@@8koi245 yeah it's "done" so it's just maintaining. You could probably use moment just fine but I find myself just needing date-fns usually and enjoy that experience more.
Pretty cool stuff! Not entirely sure about the naming though. The name seems like it will be confused with all the AI stuff these days, but perhaps it will gain extra popularity because of the confusion. Jury is still out on this one.
I would be interested how this compares to superstruct, which also has a functional approach. Since this video, valibot has doubled its size to 10kB, zod to 14.2kB and superstruct is at 3.4kB. I find it hard to compare these numbers if they can change so drastically over time. Seems like some of them are smaller because they are just missing features
A Bachelor's thesis?! As if my imposter syndrome wasnt bad enough... haha (mostly) kidding of course, this is really cool. I doubt it's meant to be a serious competitor (at this point), but it makes really good points about tree-shakeability that many projects could take a little bit more to heart! Maybe it goes somewhere, maybe not, fantastic work though!
Isn't bundle size just a lot less of an issue for backend? I always considered that the main environment for something like zod. For server-side I think I'd rather have the convenience of the z autocompletion. For lambda functions startup time I might be looking at bundle size, but I doubt this makes a noticeable difference there.
i prefer the namespaced "z.object" because it's easier for autocompletion and readability, so easier to both write and read. not sure if the tree shaking advantages of this new library hold when a whole-module-import (whatever the correct term is) is used to get these same benefits.
man living the dream of their college being able to have an actual computer science theory-heavy thesis and supported by two of the most iconic web devs in the world!
It always bothered me that you have to decide between the autocompletion ergonomics that Zod provides vs the tree-shakability that Valibot provides. I think the only way for typescript to support both of these traits is if it had proper support for nominal types. I don't usually care for nominal types, but in this instance, it would be necessary AFAIK.
In the long run, we can achieve a similar or maybe even better developer experience through a VS Code extension for Valibot. Similar to Taildwind CSS extension.
Sorry if this is duplicate. I can't see my comments. Vladimir Klepov created banditypes at 400 bytes in Feb of 2023. Maybe this individual built off of his. 642 bytes gzipped according to bundlephobia.
I'm not really knowledgeable about the whole node package ecosystem, so shout at me if I'm wrong, but I don't get it. The main purpose, as far as I see it, for object validation is when dealing with untrusted data from a client, say... on a backend server. But on a backend server, bundle size doesn't really matter as much, at least not in the realm of hundreds of bytes. I certainly far prefer the nice, easy-to-use builder chaining that zod provides over saving me from uploading an extra kb when uploading my backend app to S3.
in a perfect world you'd be right but in practice there are cases every now and then where you validate in the client. most recently i've had to come up with a flexible way to compose and store simple math formulas on a database. eval is not an option so i made my own format with JSON. it works great but with our backend it would have been incredibly complicated to set up validation for this JSON so that it adheres to the rules for parsing the formulas. since the formula is parsed in the client and the formulas are written manually to the DB by admins (trusted), there was no reason that we couldn't simply validate the JSON in the client. so the frontend will simply tell you if the stored JSON is invalid by using zod. and this isn't the first time i've ran into legitimate frontend validation.
Is there any real situation where this would result in a notable performance increase? Seems like a cool project, but I wouldn't find myself tearing Zod implementation out to replace it with this. Maybe in a new project.
What I don't like about this kind of composable functions is that you usually get `these(like(declarations()))` (yeah, you gotta read it from inside out for the order of application). I know this is easy to solve with a custom pipe function, but I don't think it's great API design until we have a pipe operator in JS.
@@mattpocockukzod is also treeshakable when you do import * as z from 'zod' which gives you the z. but does not have the piping (like valibot) It's also treeshakable when you do import {object} from 'zod' which then is the same as valibot
@@thunfisch987 tree-shakable imports from zod doesn’t allow for method chaining as they are separated as individual composable functions. You’d have to do this: z.nullable(z.string()) Instead of: z.string().nullable()
VS Code can import all this automatically and still give you suggestions. Of course, this is not quite as precise as with Zod. Maybe we will improve this with a VS extension. Alternatively you can also use a wildcard import.
Valibot has a type performance issues for basic schema. merge() seems to be the issue. Basic schema cause type instantiation deep and infinite issue and poor intellisense performance
Yeah tree shaking is nice, but come on. When you are at the point to need an end to end validator, you need anyway almost all of this stuff. If you only validate an email field, you can also just copy past a very short REGEX expression that is even smaller.
This video is impossible to undertand without undertsand what Zod is. That's fine. But it would be nice it if was clearly indicated at the start of the video that the target audience is someone who needs to understand what Zod is. I had to stop, and look it up. There wasn't even a link to it, so I had to guess and type "zod js" , so I wont get a false positive with that guy from the phantom zone.
Zod is terribly slow. Also it doesn't allow to quickly navigate to type definition's properties from their implementations in IDE. You should really try Typia instead
It’s worth noting that tree-shaking isn’t always available. It requires a build step. However, valibot is structured so that you can still only import what you actually need by using multiple direct imports, which is nice of them.
The problem with zod treeshaking IS NOT import * as z!
I’ve seen bundlers remove unreachable things from namespace imports (unless you are doing dynamic lookups).
The problem is that everything is attached to the prototype. If you import one validator, you have to import every other one (since all of the properties like .optional have to be present)
This is exactly the reason why I’m excited for the pipeline operator. Should bring analizability of pure functions, and dx convenience of method chaining together. Wonder how this is going to impact library design, and if we are to see the move away from putting things onto the prototype just to get method chaining working.
+1 I'm always checking the status of the pipeline operator proposal... my sanity depends on it.
A problem with most JS/TS validation libraries, except Zod, is that it's not possible to introspect the validation schema. So you're getting locked into the library-specific schema with no way of determining properties at runtime, which is essential in form validation libraries to generate default values for type safety, web browser constraints, etc. Without a validation standard it's hard to do anything about this, and it's easy to overlook when just looking at speed and size.
Try TypeBox, it does everything Zod does, but is based on the JSON schema standard (and to reflect you reflect on that schema)
It's as close to a standard type schema as exists.
@@BinaryReader TypeBox works as well, but as you say it's close to a standard, not an accepted standard. Which is the real problem - but even if it was, it's not that much fun to build a library if you have to adhere to a dry specification.
I guess that's why we have a dozen libraries, doing the same thing (as projects like typeschema shows when unifying most of them on the validation level), competing for microseconds (that's more fun), ignoring things like DSL lock-in and lack of introspection. Otherwise, why this fragmentation for something as fundamental as type validation?
Didn't we learn anything from the browser wars?
@@andreas.soderlund TBH, the lack of "standards" is a problem that will probably never go away in the JS/TS ecosystem, simply because the languages that have standards, by contrast, were "sponsored" by a company from the beginning.
It's my understanding that you can import stuff from zod without using z. I think you can import { object } from "zod".
Exactly
You can also do
import * as z from 'zod'
Where you have the z. Schema but sadly no piping
@@thunfisch987so could you not do the same with valibot? Import * as v. Then v.object().
Would that remove benefits of treeshaking etc too?
@@Ctrl_Alt_Elite that also works and is also tree-shakeable
but if you import 'string' you are adding methods like 'string.min' 'string.max' to your bundle even if you don't use it.
Thank you Matt!
For server side applications, runtime memory allocation is much more important than bundle size. This is where libraries like typia, ts-runtime-checks excel. They generate validation and error handling code at compile time.
Very generally, memory allocation is also very related to speed as allocating memory on the heap and then garbage collecting it is very cpu expensive. For frontend though, the bundle size is arguably more important than speed.
The problem with typia is you need to take on a lot of non-standard compiler plugins to make it work. It doesn't integrate at all with watch reload tooling, doesnt work in Deno (not least without adding extreme compiler delay (there's a reason people use swc)), and the code and schemas it emits are utterly archaic (I can't even use the schemas as they're structured so poorly we tried using it for Swagger generation...just nope). Using it also locks you into the tool and associated poor workflows for the long term.....pass.
Can't recommend it, had some wins early but turned into a footgun and ditched it for TypeBox. Havent used ts-runtime-checks, but looks like it does the same thing...so pass again.
Need proper TS tools from Microsoft to solve compiler emitted types really...and they need to integrate with swc and esbuild and be fast.
Rewriting a library that is 13.1 kilobytes in size to reduce bundle by 10-12kb, really? Isn't it going a little bit too far? Also, IMO, very questionable naming of functions such as 'email', 'object', 'string'. I don't think it's too uncommon to have a 'const email = '...';' somewhere in your code, so you'll end up either renaming that or the imported function. While 'z.email()' doesn't conflict with existing variables and also is immediately obvious to readers of the code.
Your second point is my concern, too. Hard to bring this into an existing library without rewriting a lot of your variables or having to ‘import as’ with some custom names.
Would I be wrong if I said: large projects would use most of Zod's imports and the tree shaking, after all, won't matter that much, and similarly for small projects, their overall performance won't mind an additional 8kb anyways.
Overall, in most cases, people would prefer mature projects over a tiny bit "better" ones.
Maybe that's why ZOD didn't care that much about starting with an obviously slightly better design. Or they were leaving room for competition??
Large projects should use Deepkit. Why on earth would anyone want to use runtime functions to define non type safe schemas?
People add 41kB framer-motion for fade-ins or react-hook-forms (even worse, formik) for a single form, and here we are fat-shaming zod for being 13kB but being the absolute goat
@@mskzzz goat? It's nothing compared to @deepkit/type lol
@@uziboozy4540Sorry I'm not putting application critical functionality on a library with less than 2k weekly downloads...
just tested it and you can indeed also import from zod like this. Made a quick dummy schema with import { object, string } from "zod"; and it worked perfectly fine. Ofc the import cost is a bit higher because it includes stuff like refine, transform and parse in the import, but that's honestly fine?
I accidentally do this a TON when vscode doesn't seem to understand that I'm trying to write a generic type or converting a type alias to an interface (or viceversa) and it autoimports stuff like number or string from zod.
Whoops, my bad! Should have tested it on stream.
Interesting one, my only concerns for now is long term support. If it is a students project, I’m not sure how long it will be supported
I am not "just" a student. I also have a company that will provide long-term funding for Valibot.
@@FabianHillerconsider working on your communication skills while youre at it
@@ImperiumLibertas no room for jaelousy in open source, brother
@@ImperiumLibertas Easy 🤣😂
@@ImperiumLibertas I didn't interpret his comment the way you did, and I'm glad for the clarification!
so this is basically like momentjs vs date-fns (different usecase of course)
Except moment is a legacy atm though, just worth mentioning.
@@ChristofferLunddamm already rip
@@8koi245 yeah it's "done" so it's just maintaining. You could probably use moment just fine but I find myself just needing date-fns usually and enjoy that experience more.
@ChristofferLund have you used dayjs?
@@bishowpandey453 I have not. Have you? Are you happy with it?
Pretty cool stuff!
Not entirely sure about the naming though. The name seems like it will be confused with all the AI stuff these days, but perhaps it will gain extra popularity because of the confusion. Jury is still out on this one.
Just like JavaScript did with Java 😅😅😅😅
Tbh I thought it was a cheat for Valorant until I saw its from Matt 😂
Yeah it's no bot. But just a bunch of glorified templates
Hardest thing in programming is ... ?
@@thedelanyo I'm gonna start calling JavaScript "EcmaScript", and TypeScript "Typed EcmaScript". 👀🤣
BTW - data validation is a subset of effect-schema capabilities, please take a look
The good point is that we can use the Zod's docs meanwhile the Valibot's is still in WIP.
I would be interested how this compares to superstruct, which also has a functional approach. Since this video, valibot has doubled its size to 10kB, zod to 14.2kB and superstruct is at 3.4kB. I find it hard to compare these numbers if they can change so drastically over time. Seems like some of them are smaller because they are just missing features
A Bachelor's thesis?! As if my imposter syndrome wasnt bad enough... haha (mostly) kidding of course, this is really cool. I doubt it's meant to be a serious competitor (at this point), but it makes really good points about tree-shakeability that many projects could take a little bit more to heart! Maybe it goes somewhere, maybe not, fantastic work though!
not going to worry about some tiny amount of kb difference when the marketing team adds in massive tracking scripts and massively unoptimized images
Isn't bundle size just a lot less of an issue for backend? I always considered that the main environment for something like zod. For server-side I think I'd rather have the convenience of the z autocompletion. For lambda functions startup time I might be looking at bundle size, but I doubt this makes a noticeable difference there.
Slowly but surely approaching Elm's Json.Decode package.
Hi Matt! and what do you recommend to use now for frontend react projects ?
Zod
i prefer the namespaced "z.object" because it's easier for autocompletion and readability, so easier to both write and read. not sure if the tree shaking advantages of this new library hold when a whole-module-import (whatever the correct term is) is used to get these same benefits.
man living the dream of their college being able to have an actual computer science theory-heavy thesis and supported by two of the most iconic web devs in the world!
There’s also VineJS, which is maintained by the AdonisJS team and has an API similar to zod’s but much faster, or at least they claim it is.
I cannot justify rewriting code for a couple of kilobytes.😅
This looks great, definitely want to try it out!
It always bothered me that you have to decide between the autocompletion ergonomics that Zod provides vs the tree-shakability that Valibot provides.
I think the only way for typescript to support both of these traits is if it had proper support for nominal types.
I don't usually care for nominal types, but in this instance, it would be necessary AFAIK.
In the long run, we can achieve a similar or maybe even better developer experience through a VS Code extension for Valibot. Similar to Taildwind CSS extension.
@@FabianHiller good point, thats another way it can be achieved. Would still be nice if typescript supported this.
Sorry if this is duplicate. I can't see my comments.
Vladimir Klepov created banditypes at 400 bytes in Feb of 2023. Maybe this individual built off of his. 642 bytes gzipped according to bundlephobia.
what about vs arktype?
I'm not really knowledgeable about the whole node package ecosystem, so shout at me if I'm wrong, but I don't get it.
The main purpose, as far as I see it, for object validation is when dealing with untrusted data from a client, say... on a backend server. But on a backend server, bundle size doesn't really matter as much, at least not in the realm of hundreds of bytes. I certainly far prefer the nice, easy-to-use builder chaining that zod provides over saving me from uploading an extra kb when uploading my backend app to S3.
I'd use this on the client to validate data returned by an external API for example.
It would also work really nicely for form validation.
in a perfect world you'd be right but in practice there are cases every now and then where you validate in the client. most recently i've had to come up with a flexible way to compose and store simple math formulas on a database. eval is not an option so i made my own format with JSON. it works great but with our backend it would have been incredibly complicated to set up validation for this JSON so that it adheres to the rules for parsing the formulas. since the formula is parsed in the client and the formulas are written manually to the DB by admins (trusted), there was no reason that we couldn't simply validate the JSON in the client. so the frontend will simply tell you if the stored JSON is invalid by using zod.
and this isn't the first time i've ran into legitimate frontend validation.
How is this different from superstruct ? Sounds like the same thing, slightly different api
I think that Valibot has much more features. But I may be wrong. In any case, it is implemented differently internally.
I migrated to it, it's pretty good
And here I thought this was going to be a video about Urbit. Still good to know though!
Is there any real situation where this would result in a notable performance increase? Seems like a cool project, but I wouldn't find myself tearing Zod implementation out to replace it with this. Maybe in a new project.
What I don't like about this kind of composable functions is that you usually get `these(like(declarations()))` (yeah, you gotta read it from inside out for the order of application).
I know this is easy to solve with a custom pipe function, but I don't think it's great API design until we have a pipe operator in JS.
Agree strongly with that. The chaining is much easier to read.
@@mattpocockukzod is also treeshakable when you do
import * as z from 'zod'
which gives you the z. but does not have the piping (like valibot)
It's also treeshakable when you do import {object} from 'zod' which then is the same as valibot
@@thunfisch987 tree-shakable imports from zod doesn’t allow for method chaining as they are separated as individual composable functions. You’d have to do this:
z.nullable(z.string())
Instead of:
z.string().nullable()
@@thienhuynh7962 yeah, i said that (called it piping instead of chaining)
io-ts is even smallers, and it was the librar that zod have lots of its idea.
Just horrendous docs, though
The website for it doesn't even work, the buttons don't do anything lol
Using that with SolidJS project really nice
There is something I dont understand with these libraries, why not just use typescript if you want types ?
This video made me try Zod with pipeline operator in Babel. 🔥👀🤣
I mean, this literally just looks like "superstruct" to me...
I'm confused, as a professional software developer. I watched the entire video and I still have no idea what Valibot is.
But how it affects DX when you need to import everything each time you want to use it, but you want to have autocompleting etc?
VS Code can import all this automatically and still give you suggestions. Of course, this is not quite as precise as with Zod. Maybe we will improve this with a VS extension. Alternatively you can also use a wildcard import.
Looks like pydantic for javascrpt
Valibot has a type performance issues for basic schema. merge() seems to be the issue. Basic schema cause type instantiation deep and infinite issue and poor intellisense performance
Yeah tree shaking is nice, but come on. When you are at the point to need an end to end validator, you need anyway almost all of this stuff. If you only validate an email field, you can also just copy past a very short REGEX expression that is even smaller.
Looks cool but I've been using arktype and happy with it
"with valibot you might be importing the wrong things" - Just add a "* as" to the import statement and go from there... You can replace it later.
If you do that, you're importing everything from Valibot.
@@oscarljimenez5717 but that type of import is tree shakeable
Is it? Got any reference for that? I believe you - it makes sense that it would be easy to tree-shake - but just didn't know that was a thing!
Yes is easy to refactor back to individual imports using the replace all feature of the vs code
That's also how you can have zod treeshakable
i did this myself too
superstruct has been doing this for ages
This video is impossible to undertand without undertsand what Zod is. That's fine. But it would be nice it if was clearly indicated at the start of the video that the target audience is someone who needs to understand what Zod is. I had to stop, and look it up. There wasn't even a link to it, so I had to guess and type "zod js" , so I wont get a false positive with that guy from the phantom zone.
Zod is still better.
Chaining functions is awesome.
Zod is terribly slow. Also it doesn't allow to quickly navigate to type definition's properties from their implementations in IDE. You should really try Typia instead
Deepkit >
Hey, I'm human, I swear!!!
Unfortunately zod is extremely slow and has one of the worst performances of all available validation libraries...
Inferior to Deepkit
Much slower unfortunately.
Valibot went nowhere, and that's a good thing.
0h we got aother zod
or you can just grab plain js method and use it instead 😂
just isnt necessary
I will stick with zod