Zod 4 in now in beta after about a year of development from the team. As a lot of libraries and toolset have been doing recently, Zod has been on a diet. Now it's slimmer, faster and it's been working on efficiency with TypeScript.
It was a very long time ago that Zod came out with their last major update, Zod 3. Back in 2021 we saw ver. 3 released and that's also when the uptake with Zod was building. The GitHub repo had 2,700 stars, now it has 36,500 stars. Weekly downloads were at 600,000 in 2021 and now they are at 23 million.
And as with most popular libraries, Zod is an open-source, community driven library which is written for the love of tools and libraries for all, but thankfully this one has the financial support from Clerk, one of many authentication providers that start with a free plan and scale up. We all like something for free so check out Clerk if you're looking for something like that.
Enhanced type inference capabilities
Zod 4 introduces a new API for defining object types. The z.inteface()
seems a little confusing because why should you need a interface when we already have z.object
and also are they trying to align more with TypeScript which also has object
and interface
?
Well it's a little bit similar because in TypeScript a property can be optional
in two ways:
type KeyOptional = { prop?: string };
type ValueOptional = { prop: string | undefined };
That means in the KeyOptional
you can mark the prop as optional and in the ValueOptional
you can mark the prop valve as optional.
Number formats
Number formatting has always been a pain to get right. With Zod 4 it's now got built in support for all the day to day formats we use in TypeScript. Anything else we can do with a custom format.
z.int(); // [Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER],
z.float32(); // [-3.4028234663852886e38, 3.4028234663852886e38]
z.float64(); // [-1.7976931348623157e308, 1.7976931348623157e308]
z.int32(); // [-2147483648, 2147483647]
z.uint32(); // [0, 4294967295]
z.int64(); // [-9223372036854775808n, 9223372036854775807n]
z.uint64(); // [0n, 18446744073709551615n]
Improved error handling and customisation
One of the most frustrating things a user can experience is a validation error on a site with poor error handling. Zod had the zod-validation-error
package to use with Zod 3 but now Zod 4 has that all built in and it's been improved to have prettification on top:
const error = new z.ZodError([
{
code: 'unrecognized_keys',
keys: [ 'extraField' ],
path: [],
message: 'Unrecognized key: "extraField"'
},
{
expected: 'string',
code: 'invalid_type',
path: [ 'username' ],
message: 'Invalid input: expected string, received number'
},
{
origin: 'number',
code: 'too_small',
minimum: 0,
inclusive: true,
path: [ 'favoriteNumbers', 1 ],
message: 'Too small: expected number to be >=0'
}
]);
z.prettifyError(error);
This will return the following:
✖ Unrecognized key: "extraField"
✖ Invalid input: expected string, received number
→ at username
✖ Invalid input: expected number, received string
→ at favoriteNumbers[1]
Here's to hoping that we'll be able to configure this in the future, but for now we're stuck with it like this!
Better performance optimisations
Performance has been a big focus for the latest version of Zod. Benchmarking the basics shows a vast improvement. With the object being the most heavily used and parsed, having a 10x faster version with 4 is going to make the runtimes tumble.
benchmark time (avg) (min … max) p75 p99 p999
-----------------------------------------------------------------------------
• z.object().parse
-----------------------------------------------------------------------------
zod3 857 µs/iter (604 µs … 4'106 µs) 668 µs 3'782 µs 4'106 µs
zod4 61'999 ns/iter (44'043 ns … 2'156 µs) 51'728 ns 215 µs 1'680 µs
valibot 351 µs/iter (301 µs … 973 µs) 345 µs 626 µs 742 µs
summary for z.object().parse
zod4
5.66x faster than valibot
13.83x faster than zod3
Custom email regex
When developers want to regex they'll more than likely look up online for a regex that they think is going to solve all their problems. But without knowledge of what that regex pattern is doing, and some lengthy testing, there will usually be some edge cases that are going to fall fowl of the requirements. With Zod 4 we can now select from common email expressions, as well as defining our own ones:
// Zod's default email regex (Gmail rules)
z.email(); // z.regexes.email
// the regex used by browsers to validate input[type=email] fields
z.email({ pattern: z.regexes.html5Email });
// the classic emailregex.com regex (RFC 5322)
z.email({ pattern: z.regexes.rfc5322Email });
// a loose regex that allows Unicode (good for intl emails)
z.email({ pattern: z.regexes.unicodeEmail });
This is going to help quickly create a verification pattern for emails, and should cover what we usually want to use. But for more complex requirements we can also have some custom patterns using standard string.
Summary
Well that's a few really good additions to Zod and with it's popularity growing, and this still being a Beta release of Zod 4 we can expect to see some more features being added as work continues. There are some other things that I've not covered here, but it's a very big update and I'll come back and have a look again when we get to full release. But for now I recommend you check out Zod and give it a try. It works well with Next.js too so it's something I would definitely recommend to have a look at.