Миграция n8n с SQLite на PostgreSQL: Практическое руководство

Миграция n8n с SQLite на PostgreSQL: Практическое руководство

IVOL

Запускал два инстанса n8n (на портах 5678 и 5679) с SQLite, решил перейти на PostgreSQL для масштабирования и стабильности. Делюсь опытом полной миграции включая Data Tables.


TL;DR

  • ✅ Credentials и Workflows - экспорт через UI
  • ✅ Data Tables - ручная миграция через CSV (n8n не умеет их экспортировать)
  • ⚠️ Ключевая ловушка: Foreign Key зависимости и Case-Sensitive имена таблиц в PostgreSQL
  • ⏱️ Время: ~2 часа на два инстанса

Что нужно сделать чтобы переехать на PostgreSQL

1. Подготовка PostgreSQL

Создать отдельные контейнеры для каждого инстанса n8n:

# docker-compose.yml
services:
  postgres_n8n_prod:
    image: postgres:16
    environment:
      POSTGRES_USER: n8nuser
      POSTGRES_PASSWORD: secure_password
      POSTGRES_DB: n8ndb
    volumes:
      - postgres_prod_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"

volumes:
  postgres_prod_data:

2. Экспорт Credentials и Workflows

Через n8n UI:

  • Settings → Import/Export
  • Download workflows + credentials (JSON)
  • Сохранить encryption key из старого docker-compose.yml

Важно: Не удаляй старые SQLite БД до завершения миграции!

3. Запуск n8n с PostgreSQL

# docker-compose.yml для n8n
services:
  n8n_prod:
    image: n8nio/n8n
    environment:
      DB_TYPE: postgresdb
      DB_POSTGRESDB_HOST: postgres_n8n_prod
      DB_POSTGRESDB_PORT: 5432
      DB_POSTGRESDB_DATABASE: n8ndb
      DB_POSTGRESDB_USER: n8nuser
      DB_POSTGRESDB_PASSWORD: secure_password
      N8N_ENCRYPTION_KEY: "твой_старый_ключ"  # КРИТИЧНО!

4. Импорт Credentials и Workflows

  • Пройти setup wizard (создать пользователя)
  • Settings → Import/Export → Upload JSON

Результат: Workflows и credentials работают, но Data Tables пустые.


Миграция Data Tables (сложная часть)

Проблема

n8n создает для каждой Data Table физическую таблицу вида data_table_user_{tableId}, но UI не экспортирует их данные. Нужна ручная миграция.

Решение: CSV экспорт/импорт

Шаг 1: Узнать ID таблиц

sqlite3 /path/to/database.sqlite ".tables" | grep data_table_user
# Вывод: data_table_user_aB3Cd4EfGh5IjKl6M, data_table_user_nO7Pq8RsTu9VwXy0Z, ...

Шаг 2: Экспорт структуры и данных из SQLite

# Экспорт метаданных
sqlite3 database.sqlite -header -csv "SELECT * FROM data_table" > /tmp/data_table.csv
sqlite3 database.sqlite -header -csv "SELECT * FROM data_table_column" > /tmp/data_table_column.csv

# Экспорт данных каждой таблицы
sqlite3 database.sqlite -header -csv "SELECT * FROM data_table_user_aB3Cd4EfGh5IjKl6M" > /tmp/dt_aB3Cd4EfGh5IjKl6M.csv
# Повторить для всех таблиц из Шага 1

Шаг 3: Узнать новый projectId в PostgreSQL

docker exec -it postgres_n8n_prod psql -U n8nuser -d n8ndb -c "SELECT id FROM project;"
# Вывод: xY9Za1Bc2De3Fg4Hi (новый ID, созданный при setup)

Шаг 4: Заменить старый projectId в CSV

# Найти старый projectId
head -n 2 /tmp/data_table.csv
# id,name,projectId,createdAt,updatedAt
# aB3Cd4EfGh5IjKl6M,UserData,jK5Lm6Nn7Oo8Pp9Qq,"2024-10-18 02:29:49.383",...

# Заменить на новый
sed -i 's/jK5Lm6Nn7Oo8Pp9Qq/xY9Za1Bc2De3Fg4Hi/g' /tmp/data_table.csv
sed -i 's/jK5Lm6Nn7Oo8Pp9Qq/xY9Za1Bc2De3Fg4Hi/g' /tmp/data_table_column.csv

Шаг 5: Импорт метаданных в PostgreSQL

cat /tmp/data_table.csv | docker exec -i postgres_n8n_prod psql -U n8nuser -d n8ndb -c "\COPY data_table FROM STDIN WITH (FORMAT CSV, HEADER)"

cat /tmp/data_table_column.csv | docker exec -i postgres_n8n_prod psql -U n8nuser -d n8ndb -c "\COPY data_table_column FROM STDIN WITH (FORMAT CSV, HEADER)"

Шаг 6: Создать физические таблицы

# Узнать структуру из SQLite
sqlite3 database.sqlite ".schema data_table_user_aB3Cd4EfGh5IjKl6M"
# CREATE TABLE ... ("id" integer PRIMARY KEY, "user_id" TEXT, ...)

# Адаптировать для PostgreSQL
docker exec -i postgres_n8n_prod psql -U n8nuser -d n8ndb << 'EOF'
CREATE TABLE IF NOT EXISTS "data_table_user_aB3Cd4EfGh5IjKl6M" (
  "id" SERIAL PRIMARY KEY,
  "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
  "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
  "user_id" TEXT,
  "session_id" TEXT
);
EOF

Важно: Имена таблиц в PostgreSQL Case-Sensitive! Используй двойные кавычки.

Шаг 7: Импорт данных

cat /tmp/dt_aB3Cd4EfGh5IjKl6M.csv | docker exec -i postgres_n8n_prod psql -U n8nuser -d n8ndb -c "\COPY \"data_table_user_aB3Cd4EfGh5IjKl6M\" FROM STDIN WITH (FORMAT CSV, HEADER)"

Шаг 8: Проверка

docker exec -it postgres_n8n_prod psql -U n8nuser -d n8ndb -c "SELECT COUNT(*) FROM \"data_table_user_aB3Cd4EfGh5IjKl6M\";"

Типичные ошибки и решения

1. Foreign Key constraint на projectId

Ошибка: Key (projectId)=(jK5Lm6Nn7Oo8Pp9Qq) is not present in table "project"

Решение: Заменить старый projectId на новый (см. Шаг 3-4)

2. Case-Sensitive имена таблиц

Ошибка: relation "data_table_user_ab3cd4efgh5ijkl6m" does not exist

Решение: Использовать двойные кавычки в SQL: "data_table_user_aB3Cd4EfGh5IjKl6M"

3. Пустые Data Tables не создаются

Проблема: n8n ждет существования таблиц, даже если они пустые

Решение: Создать таблицы вручную (Шаг 6) без импорта данных


Чеклист миграции

  • Создать PostgreSQL контейнер
  • Экспортировать workflows + credentials через UI
  • Сохранить encryption key
  • Запустить n8n с PostgreSQL
  • Импортировать workflows + credentials
  • Узнать список Data Tables (\dt в SQLite)
  • Экспортировать metadata (data_table, data_table_column)
  • Заменить projectId в CSV
  • Импортировать metadata
  • Создать физические таблицы
  • Импортировать данные таблиц
  • Проверить работу через n8n UI
  • Удалить временные CSV
  • Бэкап старой SQLite БД (на случай отката)

Итог

Плюсы миграции:

  • Стабильность под нагрузкой
  • Масштабируемость (репликация, шардинг)
  • Лучшая производительность для больших Data Tables

Минусы:

  • Ручная миграция Data Tables (UI не поддерживает)
  • Больше инфраструктуры (отдельный контейнер для БД)

Время миграции: 2 часа на два инстанса (с 50+ credentials, 20+ workflows, 8 Data Tables)


Автоматизация (для следующего раза)

Написал bash-скрипт для автоматической миграции:

#!/bin/bash
# migrate_n8n_sqlite_to_postgres.sh
# TODO: Опубликую на GitHub после рефакторинга

P.S. Если у тебя меньше 5 Data Tables и данные не критичны - быстрее пересоздать их вручную через UI, чем мигрировать.



#n8n #PostgreSQL #DevOps #Automation #Migration #BuildInPublic


Report Page