Skip links

Від моноліту до модульної архітектури: наш реальний досвід міграції великих продуктів на NestJS

Великі legacy-моноліти все ще дуже поширені у 2026 році — особливо в B2B SaaS, фінтех, enterprise-інструментах та маркетплейсах, які стартували 5–10 років тому. Вони працюють, приносять дохід, але з часом стають все болючішими: повільні релізи, страх торкатися коду, накопичення технічного боргу, команди заважають одна одній.

За останні 18 місяців ми успішно мігрували три великих продукти (від 400 тис. до 1,2 млн+ рядків TypeScript/Node.js) на модульну архітектуру NestJS. Ось чесна історія — що ми робили, які патерни вижили в продакшені, від чого відмовилися та які вимірювані бізнес-результати отримали.

Чому ми вирішили мігрувати (бізнес-тригери)

Рішення ніколи не було «NestJS — це круто». Воно було продиктоване конкретним болем:

  • Середній час релізу фічі — 3–6 тижнів (замість 3–7 днів)
  • Один невдалий деплой міг заблокувати весь продукт на години
  • Новим розробникам потрібно 2–3 місяці, щоб почати суттєво контриб’ютити
  • Витрати на інфраструктуру зростали швидше за трафік (бо масштабування було all-or-nothing)
  • Бізнес хотів запускати незалежні вертикалі (новий pricing engine, окремі white-label інстанси, вбудовані модулі для партнерів)

Нам потрібні були незалежне розгортання, чітка власність команд та передбачувана швидкість — без повного переписування.

Обрана стратегія: Strangler Fig + Vertical Slice + модулі NestJS

Ми свідомо не робили «великий бум-реврайт». Натомість використали комбінацію трьох патернів:

  1. Strangler Fig — поступова заміна частин старої системи новими сервісами
  2. Vertical Slice Architecture — групування за бізнес-можливостями, а не за технічними шарами
  3. NestJS як основа модулів та DI — міцна структура, відмінна підтримка TypeScript, вбудована підтримка мікросервісів

Як міграція виглядала на практиці по фазах

Фаза 0 – Підготовка (1–2 місяці)

  • Створили спільну бібліотеку з авторизацією, логуванням, конфігурацією, валідацією, обробкою помилок
  • Запровадили жорсткі правила ESLint + TypeScript для старого та нового коду
  • Налаштували монопо (Turborepo + Nx) з кешуванням та affected-командами

Фаза 1 – Витягування критичних шляхів читання (3–5 місяців) Першими витягли високонавантажені read-only ендпоінти (лістинги, дашборди, звіти) в окремі сервіси NestJS. Чому спочатку читання? Найнижчий ризик, миттєві виграші продуктивності (edge-кешування + Redis), швидкий фідбек.

Фаза 2 – Командна сторона + подієво-орієнтоване ядро (6–12 місяців) Перевели операції запису та бізнес-логіку. Ключове рішення: domain events стали основним протоколом комунікації між модулями (через RabbitMQ).

Фаза 3 – Незалежне розгортання та автономія команд (триває) Кожна вертикаль (billing, users, content, analytics тощо) стала окремим застосунком NestJS зі своїм репозиторієм, CI/CD, підмножиною схеми бази даних та пайплайном розгортання.

Архітектурні рішення, які вижили в продакшені

  • Модулі NestJS як основна межа — кожен бізнес-домен = один модуль NestJS (пізніше витягнутий в окремий застосунок)
  • Shared kernel — дуже тонкий (auth, config, logger, exceptions) — без бізнес-логіки
  • Anti-corruption layer між старим монолітом та новими сервісами
  • RabbitMQ + domain events — для всього асинхронного та міжмодульного
  • Redis — скрізь: кешування, rate limiting, сесії, тимчасові локі
  • API Gateway (Kong / Traefik) + легкий service mesh (linkerd) для роутингу та observability
  • OpenTelemetry + Grafana Tempo — трасування стало обов’язковим з першого дня

Від чого ми спробували і відмовилися

  • Повноцінні мікрофронтенди → занадто важко для наших кейсів (залишилися з module federation + Next.js)
  • GraphQL Federation → складність перевищувала цінність (залишилися з REST + tRPC всередині екосистеми)
  • Окремі бази даних на сервіс з самого початку → занадто болісно для транзакційної консистентності (залишили спільний Postgres з schema-per-service + eventual consistency)
  • Kafka → overkill для нашого масштабу (RabbitMQ ідеально впорався з усім)

Вимірювані результати після 12–18 місяців

  • Частота деплоїв — з 1–2 на місяць → 15–40 на тиждень (на вертикаль)
  • Lead time for changes — з 18–42 днів → 2–7 днів
  • Mean time to recover — з 4–12 годин → менше 45 хвилин
  • Velocity — команди видають 2,5–4× більше story points за спринт
  • Зростання витрат на інфраструктуру — майже пласке попри 2,8× зростання трафіку
  • Задоволеність розробників (внутрішній NPS) — з 4,1 → 8,7

Поточний архітектурний ескіз (2026)

  • Фронтенд → Next.js App Router + React Server Components
  • API-шар → Кілька застосунків NestJS (по одному на великий домен) + tRPC для внутрішніх викликів
  • Комунікація → RabbitMQ (події) + Redis (кеш та синхронізація)
  • Бази даних → PostgreSQL (основна) + ClickHouse (аналітика) + Redis
  • Розгортання → Kubernetes + ArgoCD + edge-функції де можливо

Підсумок

Міграція великого моноліту на модульну архітектуру NestJS — непроста справа, але дуже варта зусиль, коли зростання бізнесу стримується швидкістю інженерії.

Найбільші виграші прийшли не від самого NestJS (хоча його структура допомогла величезно), а від:

  • чітких меж власності
  • подієво-орієнтованого мислення
  • безжального фокусу на розгортаємості
  • інкрементального підходу Strangler Fig

Якщо ваш продукт уже приносить дохід, але інженерія стає вузьким місцем — починайте з малого, спочатку витягуйте читання, вимірюйте все і не намагайтеся зробити ідеально з першого разу.

This website uses cookies to improve your web experience.