Всем привет! 👋
Я — Дмитрий, автор Sury — самой быстрой библиотеки для работы со схемами. Если вы фанат Zod (а кто не фанат?), эта статья для вас. Сегодня я поделюсь неожиданными результатами тестов производительности Zod v4, расскажу, что это значит для вас, и как избежать подводных камней.
Zod v4: Стал в 17 раз медленнееб и никто этого не заметил 🙈
Начнём с небольшого кликбейта)
Это действительно так, но, конечно, не вся правда. Давайте разберёмся.
Недавно, готовясь к большому релизу Sury v10, я решил снова прогнать бенчмарки с Zod v4. Результаты? Очень интересные.
Для нетривиальной схемы Zod v4 теперь в 8 раз быстрее, чем раньше.
Но если вы создаёте схему и используете её только один раз (частый паттерн в React-компонентах), производительность резко падает — до 6 операций/мс.
Возможно, вы подумаете: «6 операций/мс — это всё ещё быстро!» Но в UI-приложениях важна каждая миллисекунда. Если вы используете Zod в React-компонентах, это может привести к заметным лагам.
Схема из бенчмарка
import { z } from "zod"; // 13.5 kB (min + gzip)
const zodSchema = z.object({
number: z.number(),
negNumber: z.number(),
maxNumber: z.number(),
string: z.string(),
longString: z.string(),
boolean: z.boolean(),
deeplyNested: z.object({
foo: z.string(),
num: z.number(),
bool: z.boolean(),
}),
});
Что изменилось в Zod v4?
Я предположил, что в Zod v4 начали использовать eval
(точнее, JIT-компиляцию через new Function
) для валидации. Это не плохо — такие библиотеки, как TypeBox, ArkType и даже Sury используют похожие техники ради скорости.
Но есть нюанс:
- Создание схемы становится медленнее (из-за шага JIT-компиляции).
Хотя для большинства пользователей это не проблема, потому что:
- Валидация становится намного быстрее (после компиляции схемы и многократного использования).
В Zod v3 создание схемы уже было не самым быстрым, а v4 пошёл ещё дальше. Если вы создаёте схемы на лету (например, в React), вы можете почувствовать замедление.
Eval/JIT — это плохо? На самом деле нет.
Существует миф, что eval
/new Function
всегда медленные или небезопасные. На практике, при аккуратном использовании, они дают потрясающую производительность. Sury активно использует JIT-компиляцию и по скорости почти не уступает Valibot, который специально заточен под быструю инициализацию.
Вот небольшое сравнение (min + gzip):
| Library | Import Size | Parse (same schema) | Create & Parse
Once |
| -------------------------------------------------- | ----------- | ----------------------------------- |
------------------- |
| [Sury](https://github.com/DZakh/sury) | 4.27 kB | 94,828 ops/ms (JIT only) | 166 ops/
ms |
| [Zod v3](https://github.com/colinhacks/zod) | 13.5 kB | 1,191 ops/ms (no JIT) | 93 ops/
ms |
| [Zod v4](https://v4.zod.dev/) | 13.5 kB | 8,437 ops/ms | 6 ops/
ms |
| [Valibot](https://valibot.dev/) | 1.23 kB | 1,721 ops/ms (no JIT) | 287 ops/
ms |
| [TypeBox](https://github.com/sinclairzx81/typebox) | 22.8 kB | 99,640 ops/ms (only assert support) | 111 ops/
ms |
| [ArkType](https://arktype.io/) | 45.8 kB | 67,552 ops/ms | 11 ops/
ms |
> Полное сравнение — в README Sury
Что делать пользователям Zod?
Если вы используете Zod на бэкенде или для долгоживущих схем — вам понравится новая скорость. Но если вы создаёте схемы динамически (например, в React), стоит провести бенчмарки или рассмотреть альтернативы.
В Zod v4 есть оба режима — обычная и JIT-валидация, так что, возможно, вы сможете подобрать оптимальный вариант. Но важно знать о компромиссах.
Также, насколько я знаю, есть способ отключить JIT-компиляцию для тех, кому это не нужно. Не уверен, что этот API публичный, но в исходниках Zod он точно есть.
Встречайте Sury — самую быструю библиотеку схем
Пора немного саморекламы! 😅
Я создал Sury, чтобы решить именно эти проблемы:
Молниеносная валидация и парсинг (благодаря JIT)
Минимальный размер и tree-shakable API
Отличная типизация и DX для TypeScript
Standard Schema и JSON Schema из коробки
Декларативные трансформации и автоматическая сериализация
Sury уже используется в продакшене многими компаниями и совместим с tRPC, TanStack Form, Hono и другими инструментами.
Пример использования Sury:
import * as S from "sury";
const filmSchema = S.schema({
id: S.bigint,
title: S.string,
tags: S.array(S.string),
rating: S.union(["G", "PG", "PG13", "R"]),
});
// On hover: S.Schema<{ id: bigint; title: string; tags: string[]; rating: "G" | "PG" | "PG13" | "R"; }, Input>
type Film = S.Output<typeof filmSchema>;
// On hover: { id: bigint; title: string; tags: string[]; rating: "G" | "PG" | "PG13" | "R"; }
S.parseOrThrow(
{
id: 1n,
title: "My first film",
tags: ["Loved"],
rating: "S",
},
filmSchema
);
// Бросит S.Error с сообщением: Failed at ["rating"]: Expected "G" | "PG" | "PG13" | "R", received "S"
// Или безопасно:
const result = S.safe(() => S.parseOrThrow(data, filmSchema));
if (result.error) {
console.log(result.error.reason);
// Expected "G" | "PG" | "PG13" | "R", received "S"
}
Да, Sury тоже использует JIT, но с акцентом на скорость как создания, так и валидации схем.
Итого
Zod v4 — отличная библиотека, и Colin (автор) проделал огромную работу, поддержав оба режима валидации.
Если для вас важна производительность — особенно в динамических или UI-heavy сценариях — обязательно проведите свои бенчмарки.
Если хотите самую быструю валидацию, минимальный размер и next-gen DX — попробуйте Sury.
(И если понравится — звезда на GitHub сделает мой день! ⭐)
Спасибо за внимание! Если есть вопросы, фидбек или хочется увидеть больше бенчмарков — пишите в комментариях на хабре или в X. До скорого! 🚀