Миграции баз данных в Node.js: Обзор инструментов и примеры

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Миграции баз данных в JavaScript (Node.js): Инструменты и практика

Разработка современных веб-приложений на Node.js редко обходится без работы с базами данных. По мере роста проекта структура таблиц, индексы и связи неизбежно меняются. Ручное выполнение SQL-скриптов на сервере — путь к хаосу и ошибкам. Решение этой проблемы — миграции баз данных (database migrations). Это механизм версионирования изменений схемы, позволяющий команде разработчиков синхронно и безопасно обновлять структуру БД.

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

1. Knex.js — универсальный конструктор запросов

Knex.js — это не просто SQL-билдер, но и полноценный инструмент для миграций и сидинга (наполнения тестовыми данными). Он поддерживает PostgreSQL, MySQL, SQLite и другие СУБД. Главное преимущество — вы пишете миграции на JavaScript, а Knex транслирует их в диалект конкретной базы.

Установка и настройка

npm install knex
npm install pg  # для PostgreSQL

Создаём файл конфигурации knexfile.js:

module.exports = {
  development: {
    client: 'pg',
    connection: {
      host: 'localhost',
      user: 'user',
      password: 'pass',
      database: 'mydb'
    },
    migrations: {
      directory: './migrations'
    }
  }
};

Создание и выполнение миграции

Создадим миграцию для таблицы пользователей:

npx knex migrate:make create_users_table

В папке migrations появится файл с меткой времени. Редактируем его:

exports.up = function(knex) {
  return knex.schema.createTable('users', (table) => {
    table.increments('id').primary();
    table.string('username', 100).notNullable().unique();
    table.string('email').notNullable();
    table.timestamps(true, true); // created_at и updated_at
  });
};

exports.down = function(knex) {
  return knex.schema.dropTableIfExists('users');
};

Применяем миграцию:

npx knex migrate:latest

Откат последней миграции:

npx knex migrate:rollback

Knex также позволяет выполнять чистый SQL внутри миграций, если требуется специфичная логика.

2. Sequelize — ORM с мощной системой миграций

Sequelize — популярный ORM для Node.js, поддерживающий PostgreSQL, MySQL, MariaDB, SQLite и MSSQL. Его CLI предоставляет удобные команды для генерации и управления миграциями, плотно интегрированными с моделями.

Начало работы

npm install sequelize sequelize-cli pg
npx sequelize-cli init

Создаём модель и миграцию одной командой:

npx sequelize-cli model:generate --name User --attributes username:string,email:string

Это сгенерирует два файла: модель models/user.js и миграцию в migrations/. Пример миграции:

'use strict';
module.exports = {
  up: async (queryInterface, Sequelize) => {
    await queryInterface.createTable('Users', {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: Sequelize.INTEGER
      },
      username: {
        type: Sequelize.STRING(100),
        allowNull: false,
        unique: true
      },
      email: {
        type: Sequelize.STRING,
        allowNull: false
      },
      createdAt: {
        allowNull: false,
        type: Sequelize.DATE
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE
      }
    });
  },
  down: async (queryInterface, Sequelize) => {
    await queryInterface.dropTable('Users');
  }
};

Применение и откат:

npx sequelize-cli db:migrate
npx sequelize-cli db:migrate:undo

3. TypeORM — миграции для TypeScript и JavaScript

TypeORM — ORM, который работает как с TypeScript, так и с чистым JavaScript. Его система миграций автоматически генерирует SQL на основе изменений в сущностях (entity), что минимизирует ручной код.

Генерация миграции из сущности

Предположим, у нас есть сущность User:

import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ length: 100, unique: true })
  username: string                    

Рекомендаций