Перейти к содержанию
  • Лента
  • Категории
  • Последние
  • Метки
  • Популярные
  • Пользователи
  • Группы
Свернуть
exlends
Категории
  1. Главная
  2. Категории
  3. Языки программирования
  4. JavaScript
  5. Drizzle ORM v2: типобезопасные миграции для Next.js с RSC

Drizzle ORM v2: типобезопасные миграции для Next.js с RSC

Запланировано Прикреплена Закрыта Перенесена JavaScript
drizzle ormnext.jsмиграции
1 Сообщения 1 Постеры 1 Просмотры
  • Сначала старые
  • Сначала новые
  • По количеству голосов
Ответить
  • Ответить, создав новую тему
Авторизуйтесь, чтобы ответить
Эта тема была удалена. Только пользователи с правом управления темами могут её видеть.
  • hannadevH Не в сети
    hannadevH Не в сети
    hannadev
    написал отредактировано
    #1

    Обложка: Drizzle ORM v2: типобезопасные миграции для Next.js с RSC и 180% ростом в 2026

    Drizzle ORM давно перестал быть просто очередной либой для работы с БД. Это инструмент, который делает миграции не просто безопасными, а удобными - особенно когда работаешь в команде и нужна синхронизация схемы между разработчиками. В 2026 году Drizzle полностью переосмыслил подход к миграциям, добавив versioning и комуtativity checks, что решает одну из самых болючих проблем - конфликты в _journal.json при параллельной разработке.

    Если ты работаешь на Next.js с Server Components, то интеграция Drizzle становится вообще кайфом: ты объявляешь схему в TypeScript, генерируешь миграции одной командой, и всё работает как надо. Плюс типизация на 100% - компилятор не даст тебе накосячить с запросом.

    Почему миграции в Drizzle - это вообще норм

    День за днём разработчики сталкивались с одной и той же проблемой: несколько веток в гите, каждая со своей миграцией, и при мерже - boom, конфликт в _journal.json. Версии разные, SQL разный, а разрешить конфликт можно только вручную. Это просто боль, особенно в больших командах.

    Drizzle v2 решил эту проблему через migration table versioning и matching by folder name instead of timestamps. Теперь каждая миграция имеет явный номер версии и название папки, что убирает рассинхронизацию. Плюс появился drizzle-kit check - команда, которая проверяет коммутативность миграций и предупредит, если что-то не так.

    Возможности drizzle-kit сейчас покрывают оба подхода к миграциям:

    • Database first - схема в БД как источник истины, ты её pull’ишь в код
    • Codebase first - схема в TypeScript как источник истины, генерируешь SQL миграции

    Выбор зависит от того, как устроена архитектура проекта и как работает команда.

    Интеграция с Next.js и Server Components - это то, что нужно

    Когда ты пишешь на Next.js 15+ с полноценными Server Components, то Drizzle встраивается просто идеально. В RSC ты можешь прямо в компоненте async/await вызвать запрос к БД - никаких API слоёв, никаких лишних рендеров.

    Вот как это выглядит в реальности. Ты создаёшь файл схемы в TypeScript - там таблицы, связи, индексы. Потом запускаешь drizzle-kit generate, и она сама создаст SQL миграции с правильными изменениями. После этого применяешь миграции через drizzle-kit push или используешь внешний инструмент - кому как удобнее.

    В Server Component потом просто импортируешь db-инстанс и пишешь запрос:

    import { db } from '@/db';
    import BookCard from '@/components/BookCard';
    
    export default async function BooksPage() {
      const books = await db.query.book.findMany({
        with: { notes: true },
      });
      
      return (
        <div>
          {books.map((book) => (
            <BookCard key={book.id} book={book} />
          ))}
        </div>
      );
    }
    

    Всё типизировано - TypeScript сразу подскажет, если ты обратишься к несуществующему полю. Нет runtime ошибок из-за опечаток в названиях колонок. Вот это и есть настоящее качество разработки.

    Процесс интеграции занимает минут пять:

    • Устанавливаешь drizzle-orm и drizzle-kit через npm
    • Создаёшь drizzle.config.ts с указанием диалекта и credentials
    • Пишешь схему в отдельном файле
    • Генерируешь и применяешь миграции
    • Используешь db в компонентах и API routes

    Типизация на уровне БД - не фантазия, а реальность

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

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

    Основные плюсы типизации в Drizzle:

    • Автокомплит в IDE - вводишь db.query.users. и видишь все доступные методы
    • Валидация на этапе разработки - не нужно ждать runtime ошибок
    • Рефакторинг без страха - переименуешь поле в схеме, и IDE покажет все места, где это повлияет
    • Генерация типов из схемы - не нужно дублировать описание структуры в TypeScript
    • Type-safe relations - связи между таблицами уже в типах, не нужно думать о join’ах вручную

    Как работают новые миграции и почему это важно

    До версии 2.0 миграции в Drizzle хранились просто по timestamp’ам. Если два разработчика создавали миграцию одновременно в разных ветках, то при мерже конфликт был гарантирован. И не просто конфликт - нужно было вручную разбираться, какой SQL код останется, потому что оба timestamp’а близки друг к другу.

    Теперь система работает иначе. Каждая миграция имеет явный номер версии (например, 0001, 0002) и хранится в отдельной папке со своим названием. При мерже веток разные миграции не конфликтуют - они просто добавляются в конец очереди. Drizzle знает, какие миграции уже были применены в БД (через таблицу миграций с новым name column), и применяет только те, которых нет.

    Особенности нового подхода:

    • Automatic upgrade - старые миграции с timestamp’ами автоматически конвертируются в новый формат
    • Smart backfilling - система понимает, какие миграции уже в БД, и не повторяет их
    • Commutativity checks - drizzle-kit check проверяет, не зависит ли порядок миграций от их очерёдности
    • Folder-based naming - папки с миграциями читаются по имени, не по дате создания
    • No more _journal.json conflicts - история миграций теперь хранится в самой таблице

    Это решает проблему, которую описывали разработчики: когда в ветке A создана миграция 0001_new_from_A, а в ветке B создана 0001_new_from_B, то при мерже был конфликт. Теперь система скажет, что это разные миграции (по содержимому папок) и применит обе в правильном порядке.

    Генерация миграций - автоматизм, которым стоит пользоваться

    Это вообще киллер-фича. Ты изменил схему в TypeScript - добавил колонку, создал индекс, добавил constraint - и запускаешь drizzle-kit generate. Drizzle сама сравнивает текущую схему с последней миграцией и создаёт новый файл с правильным SQL.

    Типичный workflow выглядит так:

    1. Редактируешь файл schema.ts - добавляешь новую таблицу или меняешь существующую
    2. Запускаешь npx drizzle-kit generate
    3. Drizzle создаёт новый файл миграции в папке drizzle/
    4. Проверяешь сгенерированный SQL - обычно он идеален, но лучше перепроверить
    5. Применяешь миграцию через drizzle-kit push или npm run migrate

    Генерация работает для всех поддерживаемых диалектов - PostgreSQL, MySQL, SQLite. При этом SQL синтаксис учитывает особенности каждой БД.

    Преимущества автоматической генерации:

    • Экономия времени - не нужно писать SQL вручную
    • Меньше ошибок - Drizzle знает синтаксис лучше, чем человек
    • Консистентность - все миграции генерируются по одним и тем же правилам
    • История в контроле версий - каждая миграция - это отдельный файл в гите
    • Возможность ревью - коллега может посмотреть сгенерированный SQL и указать на проблемы

    Синхронизация со схемой - хук после миграции

    Дрizzle понимает, что в реальных проектах может быть ситуация, когда ты меняешь БД напрямую (через миграции другого инструмента, например) или хочешь синхронизировать существующую БД. Для этого есть drizzle-kit pull - команда, которая генерирует TypeScript схему на основе текущей структуры БД.

    Чтобы автоматизировать это, можно добавить хук в gel.toml (или в конфиг БД):

    [hooks]
    after_migration_apply = [
      "npx drizzle-kit pull"
    ]
    

    Тогда после каждой применённой миграции TypeScript схема будет автоматически обновляться. Это полезно, когда работаешь с коллегами - каждый делает pull request с изменением схемы и миграцией, и после merge’а все имеют свежую версию.

    Практические примеры использования в Next.js проекте

    Вот как выглядит реальная работа с Drizzle в Next.js приложении. Допустим, у тебя есть блоговая система с постами и комментариями.

    В lib/schema.ts ты описываешь таблицы:

    import { pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core';
    
    export const posts = pgTable('posts', {
      id: serial('id').primaryKey(),
      title: text('title').notNull(),
      content: text('content').notNull(),
      createdAt: timestamp('created_at').defaultNow(),
    });
    
    export const comments = pgTable('comments', {
      id: serial('id').primaryKey(),
      postId: serial('post_id').references(() => posts.id),
      text: text('text').notNull(),
      createdAt: timestamp('created_at').defaultNow(),
    });
    

    Запускаешь drizzle-kit generate, и она создаёт файл миграции с CREATE TABLE для обеих таблиц. Потом применяешь миграцию.

    В API route’е для получения поста с комментариями (app/api/posts/[id]/route.ts😞

    import { db } from '@/lib/db';
    import { posts } from '@/lib/schema';
    import { eq } from 'drizzle-orm';
    
    export async function GET(request, { params }) {
      const post = await db.query.posts.findFirst({
        where: eq(posts.id, parseInt(params.id)),
        with: { comments: true },
      });
      
      return Response.json(post);
    }
    

    Типы для post и post.comments будут инфер’иться автоматически. TypeScript знает все поля, и IDE подскажет автокомплит.

    В Server Component для отображения поста (app/posts/[id]/page.tsx😞

    import { db } from '@/lib/db';
    import { posts } from '@/lib/schema';
    import { eq } from 'drizzle-orm';
    
    export default async function PostPage({ params }) {
      const post = await db.query.posts.findFirst({
        where: eq(posts.id, parseInt(params.id)),
        with: { comments: true },
      });
      
      if (!post) return <div>Not found</div>;
      
      return (
        <article>
          <h1>{post.title}</h1>
          <p>{post.content}</p>
          <section>
            {post.comments.map((comment) => (
              <div key={comment.id}>{comment.text}</div>
            ))}
          </section>
        </article>
      );
    }
    

    Все запросы типизированы, всё работает без runtime ошибок, и код выглядит чистым.

    Что можно делать в Drizzle:

    • SELECT с relations - автоматический join через with
    • UPDATE с условиями - set, where, returning
    • DELETE с проверками - where гарантирует, что удалишь правильное
    • INSERT RETURNING - вставляешь запись и сразу получаешь её обратно с ID
    • GROUP BY, ORDER BY, LIMIT - все как в обычном SQL, но с типизацией
    • Transactions - безопасные мультишаговые операции
    • Raw SQL when needed - если нужна специфичная оптимизация

    Что дальше развивать и на что обращать внимание

    Drizzle в 2026 году вышла на уровень, где это серьёзный инструмент для production. Но есть моменты, на которые стоит обратить внимание при переходе на новую версию. Например, если ты работаешь с ESM-модулями в TypeScript проекте, нужно убедиться, что imports в schema файле правильные - иногда drizzle-kit может не распознать расширение .js в импортах, хотя для ESM это необходимо.

    Также имеет смысл полностью разобраться с двумя подходами к миграциям - database first и codebase first - и выбрать тот, который подходит именно под архитектуру твоего проекта. Для стартапов и средних проектов codebase first обычно удобнее, потому что всё под версионным контролем. Для больших систем с легаси кодом иногда database first рациональнее.

    1 ответ Последний ответ
    0

    Здравствуйте! Похоже, вас заинтересовала эта беседа, но у вас ещё нет аккаунта.

    Надоело каждый раз пролистывать одни и те же посты? Зарегистрировав аккаунт, вы всегда будете возвращаться на ту же страницу, где были раньше, и сможете выбирать, получать ли уведомления о новых ответах (по электронной почте или в виде push-уведомлений). Вы также сможете сохранять закладки и ставить лайки постам, чтобы выразить свою благодарность другим участникам сообщества.

    С вашими комментариями этот пост мог бы стать ещё лучше 💗

    Зарегистрироваться Войти

    Категории

    • Главная
    • Новости
    • Фронтенд
    • Бекенд
    • Языки программирования

    Контакты

    • Сотрудничество
    • info@exlends.com

    © 2024 - 2026 ExLends, Inc. Все права защищены.

    Политика конфиденциальности
    • Войти

    • Нет учётной записи? Зарегистрироваться

    • Войдите или зарегистрируйтесь для поиска.
    • Первое сообщение
      Последнее сообщение
    0
    • Лента
    • Категории
    • Последние
    • Метки
    • Популярные
    • Пользователи
    • Группы