Skip to content

Commit afb9924

Browse files
jordan boyerjordan-boyer
authored andcommitted
feat: add zod4 comparison
1 parent 66f22b5 commit afb9924

File tree

7 files changed

+335
-58
lines changed

7 files changed

+335
-58
lines changed

README.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,12 @@ Here are the library used in this comparison :
3535

3636
| Date | Score | Library | Deps | Size | Light | Input | Throw | Safe | Script exec | Lib exec | Fast | Readability |
3737
| ---------- | :---: | :-----: | :---: | :----: | :---: | :---: | :---: | :---: | :---------: | :---------: | :---: | :---------: |
38-
| 2025-03-04 | 1 | arktype | 2 | 140 KB | _0_ | **1** | _0_ | **1** | 729 ms _-1_ | 586 ms _-1_ | _0_ | **1** |
39-
| 2025-03-04 | 7 | valibot | **0** | 5 KB | **1** | **1** | **1** | **1** | 70 ms **1** | 10 ms **1** | **1** | _0_ |
40-
| 2025-03-04 | 6 | zod | **0** | 60 KB | _0_ | **1** | **1** | **1** | 98 ms **1** | 34 ms _0_ | **1** | **1** |
38+
| 2025-04-11 | 1 | arktype | 2 | 140 KB | _0_ | **1** | _0_ | **1** | 406 ms _-1_ | 338 ms _-1_ | _0_ | **1** |
39+
| 2025-04-11 | 7 | valibot | **0** | 5 KB | **1** | **1** | **1** | **1** | 14 ms **1** | 4 ms **1** | **1** | _0_ |
40+
| 2025-04-11 | 6 | zod3 | **0** | 60 KB | _0_ | **1** | **1** | **1** | 25 ms **1** | 14 ms _0_ | **1** | **1** |
41+
| 2025-04-11 | 6 | zod4 | 1 | 49 KB | _0_ | **1** | **1** | **1** | 79 ms **1** | 60 ms _0_ | **1** | **1** |
42+
43+
Test have been updated on 04-11 and it now run in a M3 pro that's why the numbers are smaller now
4144

4245
Legend :
4346

@@ -60,13 +63,15 @@ Ok the build size is bigger but it does not impact the performance that much.
6063

6164
The 34ms vs 10ms seems like a 3x difference but it's the time to run 1000 iterations. So in the end it's not that much of a difference in a real world scenario.
6265

66+
For some weird reason zod4 seems to be slower than zod3
67+
6368
## Todo
6469

6570
- [ ] vanilla version ?
6671
- [ ] check error messages
6772
- [ ] check custom error messages
6873
- [ ] check custom validation rules
69-
- [ ] check the perf without using `console`
74+
- [X] check the perf without using `console`
7075

7176
## How to contribute
7277

package.json

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
"dependencies": {
1515
"arktype": "^2.1",
1616
"valibot": "latest",
17-
"zod": "^3.24"
17+
"zod3": "npm:zod@^3.24.2",
18+
"zod4": "npm:[email protected]"
1819
},
1920
"description": "Comparison of different TypeScript validation libraries",
2021
"devDependencies": {
@@ -43,12 +44,12 @@
4344
},
4445
"scripts": {
4546
"bench": "bun bench:bun --warmup 5 --runs 10",
46-
"bench:bun": "hyperfine 'bun src/arktype.ts' 'bun src/valibot.ts' 'bun src/zod.ts'",
47-
"bench:node": "hyperfine --runs 10 'node dist/arktype.js' 'node dist/valibot.js' 'node dist/zod.js'",
48-
"bench:node:strip": "hyperfine --runs 10 'node --experimental-strip-types src/arktype.ts' 'node --experimental-strip-types src/valibot.ts' 'node --experimental-strip-types src/zod.ts'",
47+
"bench:bun": "hyperfine 'bun src/arktype.ts' 'bun src/valibot.ts' 'bun src/zod3.ts' 'bun src/zod4.ts'",
48+
"bench:node": "hyperfine --runs 10 'node dist/arktype.js' 'node dist/valibot.js' 'node dist/zod3.js' 'node dist/zod4.js'",
49+
"bench:node:strip": "hyperfine --runs 10 'node --experimental-strip-types src/arktype.ts' 'node --experimental-strip-types src/valibot.ts' 'node --experimental-strip-types src/zod3.ts' 'node --experimental-strip-types src/zod4.ts'",
4950
"build": "bun scripts/build.ts && echo build success",
5051
"check": "repo-check && bun check:tsc && bun run build && bun check:once && echo check success",
51-
"check:once": "bun src/arktype.ts && bun src/valibot.ts && bun src/zod.ts && echo check:once success",
52+
"check:once": "bun src/arktype.ts && bun src/valibot.ts && bun src/zod3.ts && bun src/zod4.ts && echo check:once success",
5253
"check:tsc": "tsc --noEmit && echo check:tsc success"
5354
},
5455
"type": "module",

pnpm-lock.yaml

Lines changed: 205 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/utils.ts

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
11
type User = {
2-
name: string,
3-
age?: number,
4-
phone: string
5-
}
2+
name: string;
3+
age?: number;
4+
phone: string;
5+
};
66

7-
export function checkUserA (userA: User) {
8-
console.assert(userA.age === 42, 'userA.age should be 42')
7+
export function checkUserA(userA: User) {
8+
console.assert(userA.age === 42, "userA.age should be 42");
99
}
1010

11-
export function checkUserB (userB: User) {
12-
console.assert(userB.age === 35, 'userB.age should be 35')
13-
console.assert(userB.phone === "1234567890", 'userB.phone should be 1234567890')
11+
export function checkUserB(userB: User) {
12+
console.assert(userB.age === 35, "userB.age should be 35");
13+
console.assert(
14+
userB.phone === "1234567890",
15+
"userB.phone should be 1234567890"
16+
);
1417
}
1518

16-
export function checkUserC (userC: User) {
17-
console.assert(userC.name === "Jordan", 'userC.name should be Jordan')
19+
export function checkUserC(userC: User) {
20+
console.assert(userC.name === "Jordan", "userC.name should be Jordan");
1821
}
1922

20-
export const nbIterations = 1000
23+
export const nbIterations = 1000;

src/zod.ts

Lines changed: 0 additions & 37 deletions
This file was deleted.

src/zod3.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import {
2+
string,
3+
number,
4+
object,
5+
type infer as InferOutput,
6+
type input as InferInput,
7+
} from "zod3";
8+
import { checkUserA, checkUserB, checkUserC, nbIterations } from "./utils.ts";
9+
10+
const startTime = performance.now();
11+
12+
for (let i = 0; i < nbIterations; i++) {
13+
const userSchema = object({
14+
name: string(),
15+
age: number().default(42),
16+
phone: string()
17+
.or(number())
18+
.default("123-456-7890")
19+
.transform((phone) =>
20+
typeof phone === "number" ? phone.toString() : phone
21+
),
22+
});
23+
24+
// @ts-expect-error not exported, it's ok :p
25+
type User = InferOutput<typeof userSchema>;
26+
27+
type UserInput = InferInput<typeof userSchema>;
28+
29+
const userA = userSchema.parse({ name: "Jordan" });
30+
checkUserA(userA);
31+
32+
function createUser(input: UserInput) {
33+
const result = userSchema.safeParse(input);
34+
if (!result.success) return userA;
35+
return result.data;
36+
}
37+
38+
const userB = createUser({ name: "Romain", age: 35, phone: 1234567890 });
39+
checkUserB(userB);
40+
41+
// @ts-expect-error age should be a number
42+
const userC = createUser({ name: "Romain", age: "35" });
43+
checkUserC(userC);
44+
}
45+
46+
console.log(
47+
`Zod3 exec time for ${nbIterations} iterations :`,
48+
performance.now() - startTime,
49+
"ms"
50+
);

0 commit comments

Comments
 (0)