lenec ru

← все посты

Drizzle vs Prisma в 2026: бенчмарки, DX и где какой выбирать

19K

Сравнения Drizzle и Prisma я для себя делал дважды: в 2024-м, когда переводил один проект, и в 2026-м, когда переводил второй. За эти полтора года Prisma подтянулась, Drizzle тоже подрос, и однозначного победителя нет. Но картинка стала заметно чётче, и теперь я могу довольно уверенно сказать, в каких сценариях беру что.

В тексте — личные замеры на одном и том же сервисе и личные впечатления от работы с обоими. Версии: Prisma 5.18, Drizzle ORM 0.30, drizzle-kit 0.21, Postgres 16, Node 20, на бенче — небольшой VPS у российского хостера, 4 CPU/8 GB.

Что меряю и зачем

Один и тот же эндпоинт API: получить ленту постов с автором, лайками и тегами, страница 50 записей. То есть один основной select, два join и одно подзапросное агрегирование. Под нагрузкой — вызовы из autocannon в течение 30 секунд, 50 параллельных соединений. Pg-pool: 10. Меряю медиану, p95 и количество запросов, ушедших в БД, через pg_stat_statements.

Throughput и latency

Цифры округляю, разброс между запусками ±5%.

  • Drizzle (один SQL с join-ами): медиана 11 мс, p95 28 мс, RPS ~3500.
  • Prisma (с include): медиана 14 мс, p95 35 мс, RPS ~2700.
  • Prisma (с relationLoadStrategy: 'join'): медиана 12 мс, p95 31 мс, RPS ~3200.

Разница не катастрофическая. До перехода на стратегию join у Prisma тут был отдельный запрос на каждую таблицу, и picture получался куда грустнее. В версиях, где этой опции ещё нет, я честно отдавал Drizzle победу. Сейчас разница в основном из-за overhead query engine.

Холодный старт

На serverless и в локальной разработке холодный старт мне важен.

  • Drizzle: подтягивает несколько модулей и сразу готов. Импорт ~120 мс на холодную.
  • Prisma: запускает query engine (Rust binary). На VPS ~250–400 мс на старте.

Если у тебя cron-задачи в serverless и каждая live несколько секунд, Prisma съедает значимую часть времени. Drizzle тут заметно бодрее.

Размер бандла

Это про edge runtime и lambdas, где каждый мегабайт считают.

  • Drizzle, минимально подключённый: ~150–200 KB.
  • Prisma client + query engine: ~25 MB на disk, в bundle уезжает значительная часть зависимости от платформы.

Для классического VPS бандл не важен. Для Cloudflare Workers — критично, и Drizzle тут просто без альтернатив (Prisma идёт через отдельный Accelerate-прокси).

Developer experience

Тут уже вкус, и Prisma на коротких задачах сильно удобнее.

Что у Prisma приятно

  • schema.prisma читается как документация. Новый человек в проекте за пять минут понимает модель данных.
  • Studio из коробки. Drizzle Studio догнала, но Prisma Studio выглядит чуть отполированнее.
  • include и select покрывают 80% запросов одной строкой. Не надо думать о join-условиях.
  • Миграции через migrate dev — буквально одна команда, которая и SQL сгенерирует, и накатит, и сидов запустит.

Что у Drizzle приятно

  • Схема — обычный TS. Нет генерации клиента после каждого изменения. Поправил поле — IDE сразу подсветила все места, где этот тип используется.
  • SQL-builder тонкий и предсказуемый. То, что я пишу в TS, видно в логах БД почти один в один.
  • Миграции — обычные SQL-файлы. Их можно прочитать в PR и понять, что меняется. С Prisma на больших командах это превращалось в холивар «а можно ли руками править миграцию».
  • Нет отдельного бинаря query engine. На редких архитектурах (ARM, alpine) с Prisma я нередко ловил «бинарь не подходит для платформы».

Сложные запросы

Когда запрос выходит за пределы CRUD, картина меняется. У меня в одном проекте был отчёт с пятью CTE и оконными функциями. На Prisma я честно перешёл на $queryRaw и потерял типы. Drizzle такие штуки отлично описывает встроенным sql с тегированными литералами, и тип результата я указываю явно — но без потери остальной типизации запроса.

import { sql } from 'drizzle-orm';

const rows = await db.execute<{ day: string; total: number }>(sql`
  with daily as (
    select date_trunc('day', published_at) as day, count(*) as total
    from posts
    where author_id = ${authorId}
    group by 1
  )
  select day::text as day, total::int as total
  from daily
  order by day desc
  limit 30
`);

В Prisma такой код тоже возможен через $queryRaw, но интеграция с остальной кодовой базой получается заметно более рваной.

Миграции на больших проектах

Случай из жизни: переименовать колонку с миграцией данных. На Prisma этот сценарий до сих пор отдельная морока: сначала нужно сломать prisma migrate в одну сторону, потом руками править SQL, потом удалять снапшот. На Drizzle ты редактируешь сгенерированный SQL ровно как обычный SQL-файл и накатываешь как обычно. Для команды, у которой DBA читает каждое изменение схемы, это решает.

Где я беру Prisma

  • Стартап-MVP, важна скорость в первый месяц.
  • Продукт с CRUD-моделью, которой долгое время не нужны нестандартные запросы.
  • Команда, в которой большинство пишет на TS и не хочет писать SQL.
  • Большая часть запросов — простые select по id или поиск по индексам.

Где я беру Drizzle

  • Edge или serverless с маленьким бандлом.
  • Сервис, где BI-сторона запросов сложнее CRUD: отчёты, ETL, аналитика.
  • Проект, в котором руками подкручиваются индексы и план запроса важнее, чем экономия пары часов на схему.
  • Команда, где DBA читает миграции и хочет чистый SQL в репо.
  • Долгоживущий бэкенд, в котором не хочется зависеть от Rust-бинаря и его обновлений.

Выводы

Prisma больше про скорость старта. Drizzle больше про контроль. Если на твоём проекте оба варианта упираются в пограничные сценарии — реальные нагрузочные замеры решат за тебя. У меня сейчас на новых сервисах Drizzle просто потому, что я не хочу платить за query engine на каждом инстансе и хочу видеть SQL в логах. Но на проектах с быстрым продуктовым циклом я бы и сегодня не стал отговаривать команду от Prisma — за пару недель работы выигрыш окупает потерю на переходе.

Комментарии 0

  • Будьте первым, кто оставит комментарий.

Войдите, чтобы оставить комментарий.