Разработка базы данных по принципу Schema-First с Drizzle
Ваши TypeScript-типы говорят одно. Ваша база данных — другое. Запросы падают в рантайме, и вы остаётесь отлаживать несоответствия, которых вообще не должно было существовать.
Проектирование базы данных по принципу schema-first с Drizzle решает эту проблему, делая ваш TypeScript-код единственным источником истины. Определения схемы управляют как типами приложения, так и структурой базы данных, устраняя разрыв, который вызывает неожиданности в рантайме.
В этой статье объясняется, как работает schema-first разработка с Drizzle ORM, когда использовать различные рабочие процессы миграций и каких распространённых ошибок следует избегать.
Ключевые выводы
- Drizzle ORM следует подходу code-first, где определения схемы в TypeScript служат единственным источником истины для типов, запросов и структуры базы данных.
- Drizzle Kit предлагает два пути миграции:
pushдля быстрой локальной итерации иgenerate/migrateдля проверяемых, безопасных для команды развёртываний. - Для brownfield-проектов с существующими базами данных используйте
drizzle-kit pullдля интроспекции схемы перед генерацией миграций, чтобы избежать пересоздания таблиц. - Несоответствия имён ограничений между детерминированным именованием Drizzle и вручную созданными базами данных могут вызвать неожиданные операторы миграции.
Что на самом деле означает Schema-First в Drizzle
Drizzle по своей сути следует подходу code-first. Вы определяете таблицы, столбцы и связи в TypeScript, и это определение становится авторитетным для всего последующего — запросов, миграций и вывода типов.
import { pgTable, serial, text, timestamp } from "drizzle-orm/pg-core"
export const posts = pgTable("posts", {
id: serial().primaryKey(),
title: text().notNull(),
content: text(),
createdAt: timestamp().defaultNow(),
})
Этот файл схемы служит двум целям. Drizzle ORM использует его для типобезопасных запросов. Drizzle Kit использует его для генерации или применения изменений базы данных.
Термин “schema-first” здесь означает, что ваши определения в TypeScript ведут. База данных следует за ними.
Code-First против Database-First: понимание различия
Традиционные рабочие процессы database-first рассматривают базу данных как авторитетный источник. Вы создаёте таблицы вручную или с помощью SQL-скриптов, затем генерируете код приложения из существующей структуры.
Сравнения code-first и database-first часто смешивают эти термины. В контексте Drizzle:
- Code-first: ваша TypeScript-схема управляет изменениями базы данных
- Database-first: вы извлекаете существующую структуру базы данных в TypeScript с помощью
drizzle-kit pull
Drizzle поддерживает оба подхода. Для greenfield-проектов code-first обычно чище. Для brownfield-сценариев — присоединения к проекту с существующей базой данных — интроспекция через pull позволяет быстро начать работу.
Рабочий процесс Drizzle Kit: Push против Generate
Drizzle Kit предлагает два основных пути для применения изменений схемы к вашей базе данных.
Schema Push для быстрой итерации
npx drizzle-kit push
Push сравнивает вашу схему с базой данных и применяет изменения напрямую. Без файлов миграций. Без этапа проверки.
Это хорошо работает для:
- Сольных проектов
- Раннего прототипирования
- Локальных баз данных разработки, которые можно пересоздать
Компромисс — в видимости. У вас не будет записи о том, что изменилось и когда.
Генерируемые миграции для безопасности команды
npx drizzle-kit generate
npx drizzle-kit migrate
generate создаёт файлы SQL-миграций. migrate применяет их. Файлы хранятся в системе контроля версий, создавая аудиторский след.
Этот подход подходит для:
- Командных сред, где изменения требуют проверки
- Production-развёртываний, требующих возможности отката
- Сценариев соответствия требованиям, нуждающихся в документировании изменений
Ни один метод не является универсально правильным. Рабочий процесс Drizzle Kit учитывает оба варианта в зависимости от вашего контекста.
Discover how at OpenReplay.com.
Настройка Drizzle Kit
Ваш drizzle.config.ts сообщает Drizzle Kit, где искать схемы и хранить миграции:
import { defineConfig } from "drizzle-kit"
export default defineConfig({
dialect: "postgresql",
schema: "./src/db/schema.ts",
out: "./drizzle/migrations",
dbCredentials: {
url: process.env.DATABASE_URL!,
},
})
Drizzle поддерживает основные SQL-базы данных, включая PostgreSQL, MySQL и SQLite/libSQL, с дополнительными диалектами, такими как MSSQL и CockroachDB. Конфигурация остаётся в основном одинаковой для разных баз данных — меняются только диалект и специфичные для драйвера опции.
Распространённые ошибки, которых следует избегать
Schema-first разработка с Drizzle не обходится без проблемных моментов.
Существующие таблицы требуют осторожного обращения. Если вы внедряете Drizzle в базу данных с существующими таблицами, ваш первый generate может создать миграции, пытающиеся пересоздать всё. Сначала используйте pull, чтобы синхронизировать файл схемы с реальностью.
Интроспекция может создавать шумные различия. Извлечение из базы данных может включать имена ограничений или значения по умолчанию, отличающиеся от того, что вы написали бы вручную. Последующие генерации могут отмечать их как изменения, даже когда ничего существенного не изменилось.
Несоответствия имён ограничений вызывают неожиданные миграции. Drizzle генерирует имена ограничений детерминированно. Если в вашей базе данных другие имена (от ручного создания или другого инструмента), вы увидите операторы ALTER, переименовывающие ограничения без изменения поведения.
Рантайм-миграции требуют обработки ошибок. Если вы применяете миграции программно во время развёртывания, оберните их в правильную обработку ошибок. Неудачная миграция в середине развёртывания может оставить вашу базу данных в несогласованном состоянии.
Когда Schema-First улучшает ваш рабочий процесс
Schema-first разработка с Drizzle ORM особенно эффективна, когда:
- Вы хотите гарантии времени компиляции, что запросы соответствуют вашей схеме
- Несколько разработчиков должны координировать изменения базы данных
- Вы развёртываете в edge или serverless-окружениях, где важен размер бандла
- Вы предпочитаете SQL-подобный синтаксис абстрагированным query builder’ам
Drizzle Studio дополняет этот рабочий процесс визуальным интерфейсом для просмотра данных и тестирования запросов к вашей схеме.
Заключение
Начните с файла схемы. Определите таблицы, соответствующие вашему домену. Используйте push во время локальной итерации, затем переключитесь на generate и migrate перед привлечением коллег или развёртыванием в production.
Цель не в том, чтобы выбрать один рабочий процесс навсегда — а в том, чтобы понимать компромиссы и выбирать правильный инструмент для каждой фазы разработки.
Часто задаваемые вопросы
Да. Запустите drizzle-kit pull для интроспекции существующей базы данных и генерации соответствующей TypeScript-схемы. Это позволяет избежать деструктивных миграций. Как только файл схемы отразит текущее состояние базы данных, вы можете начать использовать generate и migrate для всех будущих изменений без риска потери данных.
Переключайтесь на generate, как только ваш проект выйдет за рамки сольного прототипирования. Как только вовлечены другие разработчики или вы развёртываете на staging или production, файлы миграций обеспечивают аудиторский след и процесс проверки, которые вам нужны. Push лучше всего оставить для локальной разработки, где базу данных можно безопасно пересоздать.
Да. Drizzle поддерживает определение внешних ключей непосредственно в вашей схеме и предоставляет relations API для объявления отношений один-к-одному, один-ко-многим и многие-ко-многим. Эти связи обеспечивают работу relational query API, который позволяет получать вложенные данные типобезопасным способом без написания сырых SQL JOIN'ов.
Оба являются code-first ORM, но различаются по философии. Prisma использует собственный язык схемы и генерирует из него клиент. Drizzle определяет схемы на чистом TypeScript, давая вам прямой контроль над SQL-выводом и меньшие размеры бандлов. Drizzle по дизайну ближе к SQL, в то время как Prisma больше абстрагирует его.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.