25 авг. 2024 г.·8 мин чтения

Kysely, Drizzle или чистый SQL для TypeScript-бэкендов

Kysely, Drizzle и чистый SQL: сравните типобезопасность, контроль миграций и запасные выходы, чтобы выбрать подходящий вариант для неудобных правил продукта.

Kysely, Drizzle или чистый SQL для TypeScript-бэкендов

Почему этот выбор быстро усложняется

Выбор между Kysely, Drizzle и чистым SQL кажется простым, пока ваше приложение еще умещается на доске. Вам нужны быстрые запросы, чистый код и рефакторинг, который не превращается в неделю стресса. На бумаге все три варианта могут подойти.

Проблемы начинаются, когда продукт перестает быть аккуратным. Маленькое приложение становится настоящим бизнесом, а у настоящего бизнеса быстро накапливаются неудобные правила. В биллинге нужны пропорциональные начисления и сложные случаи с возвратами. Отчетам нужны групповые итоги, фильтры и выгрузки, которые должны в точности совпадать с цифрами у финансов. Права доступа перестают быть просто «админ» и «пользователь» и превращаются в набор исключений.

Именно тогда инструменты для базы данных показывают, что они умеют на самом деле.

Инструмент может отлично подходить для обычного CRUD, но начать мешать в тот момент, когда нужен грязный join, вручную настроенный запрос или миграция, которую нужно провести в очень строгом порядке. Команды обычно хотят сразу две вещи: скорость сейчас и безопасность потом. Эти цели тянут в разные стороны.

Стартап может начать с нескольких таблиц для аккаунтов, подписок и событий. Через шесть месяцев той же команде уже нужны биллинг по фактическому использованию, журналы аудита, soft delete, проверки ролей и отчет, который сравнивает текущий месяц с предыдущими 13 месяцами. Код ломается не потому, что команда стала неаккуратной. Он ломается потому, что работа изменила форму.

Неправильный выбор тихо разносит боль по всему проекту. Разработчики избегают рефакторинга, потому что типы не говорят всей правды. Миграции становятся напряженными, потому что один неверный шаг может заблокировать выкладку. Код запросов становится труднее читать, и каждая необычная фича превращается в спор о том, оставаться внутри инструмента или опускаться до SQL.

Вот почему это решение так долго не отпускает. Оно влияет на каждую фичу, которую вы строите после выхода первой версии.

Что дает каждый вариант в первый день

На старте разница между этими вариантами не в долгосрочной теории. Она в том, как команда пишет первый настоящий запрос, добавляет первую таблицу и исправляет первую ошибку, не теряя полдня.

Kysely с самого начала ближе всего к SQL. Это типизированный конструктор запросов, так что вы все еще думаете в терминах joins, фильтров и подзапросов, но TypeScript ловит неверные имена колонок и сомнительные формы результата. Если ваша команда уже любит SQL, Kysely обычно кажется знакомым уже через час.

Drizzle дает более цельный подход. Вы описываете схему, пишете запросы и ведете миграции в одном стиле. Многим командам так проще держать все в голове. Первый плюс здесь — единообразие. Описание таблицы в коде часто становится первым местом, куда все смотрят.

Чистый SQL — самый прямой вариант. У вас полный контроль, нулевая абстракция, и вы никогда не спорите с библиотекой, когда запрос становится странным. Такая свобода отлично подходит, если команда умеет хорошо писать SQL, но тогда на вас ложится больше работы вокруг типов, повторного использования запросов и проверок безопасности.

Привычки команды важны не меньше, чем синтаксис. Бэкенд-команда, которая и так внимательно проверяет SQL, часто двигается быстрее с Kysely или чистым SQL, чем с более высоким уровнем абстракции, которому она не доверяет. Продуктовая команда с разным уровнем опыта часто быстрее приходит к Drizzle, потому что путь со схемой и миграциями там ощущается более направленным.

Простое правило обычно работает хорошо. Выбирайте Kysely, если разработчикам нужна помощь с типами, но они не хотят терять ощущение SQL. Выбирайте Drizzle, если команде нравится подход schema-first и нужен один кодовый шаблон для схемы, запросов и миграций. Выбирайте чистый SQL, если запросы уже необычные, а команда достаточно дисциплинирована, чтобы сама выстроить защитные правила.

Последняя часть важнее, чем многие признают. Инструмент не исправляет слабые привычки работы с базой данных. Он лишь делает текущие привычки удобнее.

Как типобезопасность ощущается в реальном коде

Типобезопасность сначала помогает в самых скучных местах. Вы замечаете ее, когда соединяете три таблицы, переименовываете одну колонку, а редактор еще до запуска подсказывает, что сломалось.

Автодополнение делает много полезной работы на соединениях и именах колонок. Простую опечатку вроде users.email вместо user.email в чистом SQL легко не заметить, а типизированный билдер ловит ее быстро. Это экономит время на обычной backend-работе, а не только на редких пограничных случаях.

Kysely больше всего похож на ручную запись SQL. Запрос выглядит почти как SQL, поэтому разработчики, которые мыслят SELECT, join'ами и предикатами, обычно быстро привыкают. Вы получаете проверки выбранных колонок и формы результата, что особенно помогает, когда отчетный запрос возвращает данные с алиасами или во вложенной структуре.

Drizzle раньше начинает требовать более строгого подхода. Он сильнее продвигает решения в описание таблиц, поэтому схема становится более важной частью ежедневной разработки. Это удобно, когда команде нужен один понятный источник правды в TypeScript. Но из-за этого на формирование таблиц и связей уходит больше времени, прежде чем код запросов начинает ощущаться естественно.

Именно расхождение схемы быстрее всего подрывает уверенность. Если база данных изменилась, а сгенерированные или объявленные типы отстают, редактор создает ложное чувство безопасности. Код выглядит чистым, но production падает, потому что колонка изменила тип или поле, которое раньше было nullable, перестало быть nullable. Никакой инструмент не решает это сам по себе. Команде нужна привычка, которая держит схему и типы в синхроне.

Чистый SQL по умолчанию не дает таких ограждений. С ним все еще можно писать отличный код, и иногда это самый ясный вариант, но тогда вам нужны тесты и внимательное ревью, чтобы ловить простые ошибки. Многие команды думают, что заметят каждую опечатку и каждое несовпадение. Обычно это не так.

На маленькой биллинговой странице разница становится очевидной. Если там соединяются subscriptions, invoices и customers, Kysely и Drizzle обычно ловят неверные имена колонок еще во время набора. Чистый SQL часто ждет до момента выполнения, когда ошибка стоит дороже и ее дольше искать.

Как ощущаются миграции после шестого месяца

Первые несколько миграций кажутся легкими. Шестой месяц — это когда появляется настоящая боль. К этому времени вы уже не добавляете одну чистую таблицу. Вы переименовываете колонки, которые все еще нужны отчетам, дозаполняете старые строки и стараетесь не уронить production в два часа ночи.

Drizzle часто ощущается плавно в начале, потому что схема и процесс миграций находятся рядом. Командам, которым нравится TypeScript-first workflow, обычно это по душе. Kysely ощущается свободнее. Он дает инструменты для миграций, но не заставляет придерживаться одного стиля описания схемы, поэтому у команды больше свободы и больше пространства для несогласованности. Чистый SQL в первый день кажется медленнее, зато через шесть месяцев часто читается как самое честное описание того, что изменилось.

Один практический вопрос важнее, чем личные предпочтения к инструменту: кто пишет миграции и кто их проверяет? Если миграции пишет прикладная команда, но никто не смотрит на планы запросов, риск блокировок или шаги отката, проблемы начинаются быстро. Миграция — это не просто стиль кода. Это операционное изменение.

Когда вы сравниваете инструменты, проверяйте их на тех изменениях, которые обычно и причиняют боль: переименование таблицы или колонки без поломки старого кода, дозаполнение миллионов строк безопасными партиями, откат, когда половина выката уже прошла, и синхронизация кода приложения с изменениями схемы.

Вот здесь чистый SQL часто выигрывает в рискованных production-задачах. Аккуратный SQL-скрипт делает намерение очевидным. Видно, какие шаги чувствительны к блокировкам, можно разбить работу на партии и добавить проверки на каждом этапе. Это особенно важно, когда на кону биллинговые данные, журналы аудита или отчеты для клиентов.

Также полезно разделять изменения схемы и исправления данных. Сначала добавьте nullable-колонку. Затем выкатите код приложения. Потом запустите дозаполнение как отдельную задачу. И только после этого делайте колонку обязательной или удаляйте старую. Команды пропускают этот шаг, потому что он кажется медленным. Обычно он гораздо быстрее, чем исправлять плохой релиз.

Смешанные подходы живут дольше догмы. Используйте Drizzle или Kysely для простых и частых изменений, которые команда делает каждую неделю. Переходите на SQL, написанный вручную, когда миграция затрагивает много данных, требует аккуратной логики отката или зависит от поведения конкретной базы. Такой баланс дает скорость, не притворяясь, что каждое изменение достаточно безопасно для сгенерированных файлов миграций.

Когда правила продукта становятся неудобными

Сделайте SQL понятнее
Сделайте сложные запросы проще для чтения, тестирования и изменений.

Настоящие продукты перестают выглядеть аккуратно, когда накапливаются pricing, права доступа и отчетность. Тариф может считаться по количеству мест, не брать плату с внутренних пользователей, применять налоговые правила для разных стран и скрывать часть строк от сотрудников поддержки. Вот тогда чистые примеры перестают помогать.

Drizzle особенно хорош, когда ваша модель данных хорошо ложится на таблицы и связи. Вы описываете схему, получаете сильные типы и двигаетесь быстро. Проблемы начинаются, когда один запрос вдруг обрастает пятью условиями, которые действуют только по вторникам, или когда логика ценообразования зависит сразу от состояния биллинга, feature flags и истории аккаунта. Сделать это можно, но запрос часто становится труднее читать.

Kysely обычно лучше прогибается под такое давление. Его билдер ближе к SQL, поэтому необычные соединения, условные фильтры и вычисляемые поля ощущаются менее натянуто. Если вам нужно добавлять части запроса по шагам, исходя из входных данных или правил продукта, Kysely часто читается ближе к тому запросу, который вы и хотели написать.

Чистый SQL по-прежнему остается честным ответом для части работы. Страницы поиска, финансовые выгрузки, админские отчеты и запросы ранжирования часто требуют оконных функций, общих табличных выражений, вручную настроенных индексов или возможностей конкретной базы. Прятать это за красивым API иногда просто тратит время.

Команды обычно чувствуют боль в одних и тех же местах: биллинговые правила, зависящие от нескольких таблиц и диапазонов дат, проверки доступа, которые меняются по роли, мультиарендности и состоянию ресурса, отчеты, где группировка и сортировка идут не так, как ожидалось вначале, и поисковые запросы с оценкой релевантности или нестандартной сортировкой.

Запасные выходы важны, потому что дедлайнам все равно на чистоту абстракций. У Drizzle есть выходы в SQL, но стоит заранее проверить, насколько естественно они ощущаются, прежде чем окончательно остановиться на нем. Kysely тоже позволяет опускаться ниже без резкой смены мышления, и именно поэтому многие команды держатся за него дольше.

Если ваша команда каждую неделю тянется к SQL, написанному вручную, это не провал. Это значит лишь, что правила вашего продукта ближе к базе данных, чем хочет инструмент, ориентированный на таблицы. В таком случае используйте один простой тест: когда запрос становится странным, сколько лишнего трения появляется, прежде чем вы сможете просто написать его?

Простой способ выбрать для своей команды

Для большинства команд это не философский спор. Это проверка на читаемость и проверка на изменения. Выбирайте тот вариант, который команда все еще понимает, когда простые таблицы уже позади, а неудобные правила продукта начинают множиться.

Начните не с документации, а с backlog. Достаньте оттуда три самых сложных запроса, которые вам уже точно понадобятся. Включите самые раздражающие: правило биллинга с исключениями, проверку прав доступа с соединениями и отчет, который проходит через несколько таблиц.

Потом прогоните один и тот же небольшой тест в каждом варианте. Напишите эти три запроса. Добавьте один отчет, который соединяет несколько таблиц и возвращает именно ту форму, которую реально использует ваш API. Сделайте одну миграцию с переименованием колонки и дозаполнением данных. Потом вместе прочитайте финальный код и спросите себя, насколько многое понятно с первого взгляда.

Этот тест скажет больше, чем любая таблица возможностей. Инструмент может выглядеть аккуратно в первый день и начать шуметь через шесть месяцев, особенно когда запросы перестают попадать в счастливый сценарий.

Мое предвзятое мнение простое. Если вашей команде чаще нужно выразить SQL, чем описывать файлы схемы, Kysely обычно ощущается естественнее. Если команде нравится schema-first подход и хочется тесной связи между таблицами, типами и миграциями, Drizzle может подойти лучше. Если в продукте много странных правил отчетности, специфичных возможностей базы или просто ручных запросов, чистый SQL по-прежнему трудно чем-то заменить.

Еще одно правило важнее, чем многие признают: оставьте чистый SQL доступным даже если вы выбрали билдер. Часть, которая спорит с инструментом, не станет проще только потому, что вы остались ему верны.

Хорошая проверка на здравый смысл проста и практична. Если код запроса читается почти как обычный SQL, будущая версия вас поблагодарит. Если переименование плюс дозаполнение уже кажутся рискованными, миграции потом будут болезненными. Если межтабличные отчеты быстро становятся громоздкими, работа с отчетностью будет тормозить. И если объяснить код может только один человек, выбор уже обходится слишком дорого.

Лучший вариант — обычно тот, который делает обычную работу скучной и оставляет вам понятный запасной выход для странных случаев.

Пример: SaaS-приложение с биллингом и отчетами

Выберите подходящий инструмент
Обсудите с Oleg ваши реальные запросы, привычки команды и требования к отчетам.

Представьте небольшой SaaS-продукт с четырьмя таблицами, с которыми вы работаете каждый день: users, plans, invoices и feature_limits. На первой неделе все три варианта кажутся достаточно простыми. Вы создаете пользователя, привязываете тариф, выставляете счет и проверяете, может ли аккаунт использовать выгрузки или дополнительные места.

Спокойная часть заканчивается, когда правила биллинга перестают быть аккуратными. Один клиент обновляет тариф в середине месяца, сохраняет часть пробного кредита и позже получает частичный возврат. Другой понижает тариф после того, как уже использовал больше мест, чем позволяет младший план. Теперь код должен объяснять деньги, а не просто доставать строки.

Для панели клиента Drizzle часто сначала кажется самым удобным. Вы можете загрузить пользователя, текущий тариф, последний счет и текущие лимиты в стиле, который остается близким к прикладному коду. Команды, которым нравится описывать схему в TypeScript, обычно двигаются здесь быстро.

Kysely начинает ощущаться лучше, когда у этой панели появляются зубы. Может понадобиться показать текущее использование против лимита, сколько дней осталось в пробном периоде, статус неудачного платежа и примерный расчет следующего счета в одном ответе. Kysely держит больше SQL на виду, поэтому соединения, подзапросы и условные фильтры легче читать, когда запрос становится длиннее.

Админский отчет обычно быстрее показывает разницу между инструментами, чем обычный CRUD. Допустим, финансам нужен ежемесячный отчет по выручке по тарифам, возвратам, конверсиям из пробного периода и аккаунтам, которые превысили лимиты. Такому запросу могут понадобиться CTE, групповые итоги, разбивка по датам и, возможно, оконная функция. Kysely хорошо справляется с таким типом работы. Чистый SQL все еще кажется самым естественным, когда сам запрос уже живет у вас в голове как SQL.

Держите чистый SQL в этом приложении небольшим и осознанным. Используйте его для математики пропорциональных начислений, которая должна в точности совпадать с правилами счета, для отчетов по возвратам, где каждая копейка должна сходиться, и для одного сложного отчета, который напрямую использует возможности базы данных.

Проблемы начинаются тогда, когда чистый SQL расползается по обработчикам маршрутов, и каждый запрос зашивает чуть разные правила биллинга.

Вот настоящий тест. Drizzle приятно использовать для обычных таблиц и простых чтений. Kysely дает больше пространства, когда накапливаются отчеты и условные соединения. Чистый SQL выигрывает в неудобных углах, но только если вы изолируете его и проверяете итоги. Оценивайте выбор по изменениям биллинга на шестом месяце, а не по тому, как быстро первая таблица users собирается без ошибок.

Ошибки, которые команды совершают

Команды часто принимают это решение после красивой демо-версии. Это плохой фильтр. Аккуратный CRUD-экран почти ничего не говорит о тех самых неудобных 10% запросов, которые появятся позже: billing edge cases, правила доступа, выгрузки отчетов и вопросы вроде «почему эта сумма по вторникам выглядит неверной?»

Типобезопасность помогает, но команды часто просят от нее слишком многого. Она может поймать опечатку в названии колонки или неверное предположение о null. Но она не скажет вам, что соединение изменило набор результатов, миграция удалила данные, которые вам все еще нужны, или отчет соответствует не тому бизнес-правилу.

Именно поэтому тесты все еще важны. Если pricing, счета или контроль доступа могут стоить денег или закрыть пользователям доступ, пишите тесты вокруг поведения SQL, а не только вокруг типов TypeScript.

Еще одна распространенная ошибка — считать чистый SQL провалом. Команды прячут его за слоями хелперов, потому что хотят, чтобы кодовая база выглядела «чистой». Через шесть месяцев никто не может разобрать путь запроса, код билдера выглядит как головоломка, а один честный SQL-файл был бы проще.

Проблема не в чистом SQL. Проблема в безымянном, разбросанном по коду и неотревьюенном чистом SQL. Держите запасные выходы явными, складывайте сложные запросы в одно место и тестируйте их так же, как любую другую бизнес-логику.

Миграции создают боль другого рода. Команды слишком тесно связывают изменения схемы с релизами приложения, и один выкат уже ожидает колонку, которую другой выкат еще не добавил. В локальной разработке это работает, а во время реального запуска ломается.

Более безопасная привычка намеренно скучная: сначала добавьте, потом дозаполните, затем переключите чтение и запись, и только после этого удаляйте старые колонки. Это занимает больше времени, но избавляет от ночных исправлений.

Медленные запросы вскрывают последнюю ошибку. Многие команды выбирают инструмент, не спросив, кто будет разбирать production-инциденты. Когда панель начинает тормозить или индекс перестает помогать, кому-то нужно прочитать сгенерированный SQL, посмотреть план выполнения и решить, что менять.

Если никому в команде некомфортно делать это, самая приятная абстракция вас не спасет. Инструмент должен делать SQL проще для проверки, а не проще для игнорирования.

Быстрые проверки перед тем, как решиться

Ускорьте решения по бэкенду
Используйте короткий CTO-разбор вместо недель споров об инструментах.

Перед тем как зафиксировать слой работы с базой данных, задайте несколько прямых вопросов. Большинство инструментов нормально выглядят на простом CRUD. Проблемы начинаются позже, когда отчет ведет себя странно, правила биллинга множатся или одно переименование колонки затрагивает половину кода.

  • Может ли один разработчик прочитать сложный запрос и объяснить его таблица за таблицей без догадок?
  • Можно ли переименовать колонку и быстро увидеть все поломки в коде, тестах и миграциях?
  • Можно ли смешать код билдера и чистый SQL для одного неудобного случая без странных оберток?
  • Может ли команда посмотреть финальный SQL перед релизом и поймать плохое соединение или полное сканирование?
  • Может ли новый разработчик понять правила за день и вскоре после этого сделать безопасное изменение?

Эти проверки звучат просто, но они показывают реальный компромисс. Если команде трудно объяснить сложный запрос, чистый SQL быстро превратится в копипасту. Если инструмент делает SQL трудным для проверки, вы можете выпустить медленные запросы с красивыми типами TypeScript и вообще не понимать, что ударило по базе данных.

Переименование колонок — еще один хороший стресс-тест. Чистый API мало что значит, если переименование превращается в поиск по всему проекту среди миграций, файлов схемы и запросов, написанных вручную. Попробуйте это до того, как решитесь. Если даже в маленьком демо процесс ощущается напряженно, в production он будет еще хуже.

Я бы доверил тому варианту, который делает ошибку заметной. Скрытая магия — обычно первое, о чем команда потом жалеет.

Один небольшой эксперимент расскажет больше, чем таблица возможностей. Соберите одни и те же три задачи в каждом варианте: экран поиска с фильтрами, дозаполнение данных для биллинга и отчет с одним некрасивым join'ом. Потом спросите, кто в команде сможет поддерживать этот код через шесть месяцев. Ответ обычно честнее любого бенчмарка.

Что делать дальше

Многие команды понимают это слишком поздно: трудная часть — не первая неделя. Она начинается примерно на шестом месяце, когда кому-то нужен странный отчет, рискованное исправление данных или миграция, которая затрагивает живых клиентов. Короткий spike расскажет вам больше, чем еще одно длинное совещание.

Используйте одну небольшую фичу как тест. Возьмите что-то достаточно неудобное, но реальное, например корректировку биллинга, отчет с групповыми итогами или правило доступа с несколькими соединениями. Соберите один и тот же кусок end-to-end, а потом сравните, как читается код, насколько удобна миграция и как легко опуститься до обычного SQL, когда билдер начинает спорить.

Держите эксперимент коротким. Ограничьте его одним-двумя днями. Включите один обычный запрос, один неудобный запрос и одно изменение схемы. Запишите, где разрешен чистый SQL, кто его проверяет и какой стиль миграций вы будете тестировать.

Это правило для чистого SQL важнее, чем ожидают многие. Если его не записать, каждый неудобный запрос превращается в новый спор. Держите правило простым. Используйте билдер для обычных чтений и записей. Используйте чистый SQL для возможностей конкретного вендора, тяжелой отчетности, массовых обновлений или всего, что становится менее читаемым, если загонять это в абстракции.

Стиль миграций тоже нужно проверять не в теории, а на практике. Сгенерированные файлы поначалу могут казаться очень быстрыми. SQL, написанный вручную, может казаться безопаснее, когда изменение чувствительное. Выберите один подход, прогоните его через code review и посмотрите, что произойдет, когда кто-то другой в команде попробует разобраться в нем через неделю.

Если команда все еще разделена, поможет внешний разбор. На oleg.is Oleg Sotnikov проводит ревью схемы, процесса миграций и границ запросов в рамках консультаций Fractional CTO. Короткий разбор может сэкономить недели переделок, когда логику биллинга, отчетность или старые данные начинает сложнее вписывать в код.

Выбирайте вариант, которому ваша команда будет доверять даже тогда, когда простые запросы закончатся.

Часто задаваемые вопросы

С какого варианта большинству команд стоит начать?

Начните с вашего реального backlog, а не с таблицы возможностей. Если команда мыслит в SQL и ожидает неудобные соединения и отчетные запросы, Kysely часто оказывается самым безопасным выбором по умолчанию. Если команде удобнее, когда схема, запросы и миграции живут в одном TypeScript-стиле, Drizzle обычно подходит лучше. Если продукт уже зависит от сложной отчетности или специфичного SQL, написанного под конкретную базу, чистый SQL может сэкономить время.

Не слишком ли рискован чистый SQL для боевого приложения?

Не если относиться к нему как к обычной бизнес-логике. Держите его в понятных файлах, проверяйте в ревью и тестируйте итоги и пограничные случаи. Чистый SQL становится рискованным, когда разработчики раскидывают его по обработчикам, а правилами никто не владеет.

Заменяет ли типобезопасность тесты?

Нет. Типы помогают поймать опечатки в колонках, неверные предположения про null и часть ошибок в форме результата. Но они не доказывают, что ваша биллинговая математика, соединения или правила доступа совпадают с правилами продукта, поэтому тесты все равно нужны.

Что лучше справляется со сложными отчетами?

Для сложных отчетов чистый SQL обычно дает самый прямой путь. Kysely подходит очень близко, потому что остается рядом с SQL и без особого трения работает с соединениями, подзапросами и условными фильтрами. Drizzle хорошо справляется с более простыми чтениями, но длинные отчетные запросы там чаще становятся шумными.

Что делает миграции болезненными спустя несколько месяцев?

Боль обычно начинается тогда, когда команды слишком тесно связывают изменения схемы с релизами приложения. Более безопасный путь прост: сначала добавить новую колонку, затем выкатить код, который умеет работать в обеих формах, потом отдельно дозаполнить старые данные и только после этого убрать старый путь. Такой подход снижает риск выката, каким бы инструментом вы ни пользовались.

Можно ли смешивать query builder и чистый SQL?

Да, и большинству команд это нужно. Используйте билдер для обычных чтений и записей, а затем переходите к SQL для массовых обновлений, возможностей конкретного вендора, финансовых отчетов или всего, что хуже читается через абстракции. Так ежедневная работа остается простой, и вы не загоняете себя в угол.

Когда Drizzle подходит лучше всего?

Drizzle хорошо подходит командам, которым нравится workflow, где сначала идет схема, а в TypeScript есть один понятный источник правды для таблиц, типов и миграций. Он комфортен для CRUD и обычных backend-фич. Если правила продукта остаются довольно прямыми, Drizzle помогает держать ежедневную работу аккуратной.

Когда Kysely подходит лучше всего?

Kysely хорошо работает, когда разработчики уже думают в терминах SELECT, соединений, предикатов и подзапросов. Он дает проверки типов и при этом держит запрос близко к обычному SQL. Такой баланс помогает, когда фильтры, соединения и вычисляемые поля меняются в зависимости от входных данных или бизнес-правил.

Как протестировать эти варианты перед выбором?

Сделайте короткий спайк на реальной задаче. В каждом варианте напишите один обычный запрос, один неудобный запрос с соединениями и условиями и одну миграцию с переименованием плюс дозаполнением. Потом спросите команду, какую версию все еще можно читать и менять без догадок.

О чем команде нужно договориться перед выбором?

Решите, кто может писать чистый SQL, кто проверяет миграции и кто смотрит на финальный SQL, когда запрос начинает тормозить. Лучше договориться об этом до роста кодовой базы, иначе каждый неудобный случай превращается в новый спор. Если команде нужен второй взгляд, короткий CTO-ревью может заранее найти слабые места в схеме, миграциях и границах запросов.