JavaRush /Курси /ChatGPT Apps /Розгортання на Vercel: репозиторій, env‑змінні, preview →...

Розгортання на Vercel: репозиторій, env‑змінні, preview → production

ChatGPT Apps
Рівень 7 , Лекція 3
Відкрита

1. Навіщо вам Vercel для ChatGPT App

У попередніх лекціях ми запускали GiftGenius локально й підʼєднували його до ChatGPT через Dev Mode і тунель. Тепер час зробити ще один крок до «дорослого» продакшену — перенести цей самий код на Vercel.

На цьому етапі у вас уже є робочий застосунок GiftGenius (наш умовний навчальний App). Локально він працює на Next.js 16 з MCP‑endpointʼом (наприклад, /api/mcp) і зібраний на основі офіційного ChatGPT Apps SDK Next.js Starter.

Можна було б піти шляхом «я орендую VPS, вручну ставлю Node, nginx і сам(-а) все налаштовую». Але для Next.js це приблизно як писати фронтенд на чистому document.write у 2025 році. Працює, але ви явно ускладнюєте собі життя.

Vercel підходить вам з кількох причин.

По‑перше, він має вбудовану підтримку Next.js: автоматично налаштовує збірку, SSR, статику, edge‑рівень і безсерверні функції. Для ChatGPT App це особливо зручно, адже віджет і MCP‑endpoint розгортаються «в один клік» і працюють в одній інфраструктурі.

По‑друге, Vercel дає CI/CD «з коробки»: ви підʼєднуєте Git‑репозиторій — і кожен push створює нове незмінне (immutable) розгортання з унікальним URL. Для гілки main це вважається Production, для інших гілок — Preview.

По‑третє, у Vercel зручно працювати із середовищами та секретами. Він чітко розділяє env‑змінні на Development, Preview і Production, зберігає їх зашифрованими та дає змогу легко «прокидати» в Next.js. Це саме те, що потрібно для ChatGPT App: ключі та URL MCP‑сервера мають змінюватися залежно від середовища.

По‑четверте, у Vercel є зручні відкати: якщо новий реліз пішов не так, можна швидко «підняти» попереднє успішне розгортання й повернути систему до робочого стану. Це знижує «страх деплою» та заохочує невеликі, часті релізи.

І нарешті, Vercel — компанія‑розробник Next.js. Вони пристосовували Next.js під свою інфраструктуру, а інфраструктуру — під Next.js. Користуючись Vercel, ви ще не раз відчуєте, наскільки плавно й швидко все працює буквально в кілька кліків. Думаю, вам сподобається.

2. Стартова точка: структура проєкту GiftGenius

За планом курсу наш GiftGenius живе в одному репозиторії. Є два варіанти організації, і обидва підходять для Vercel:

1) Монорепозиторій із кількома застосунками — наприклад:

giftgenius/
  apps/
    web/   # Next.js (віджет + MCP)
    mcp/   # окремий MCP‑сервер (якщо ви його винесли)

2) Один Next.js‑проєкт, де і віджет, і MCP живуть разом (на старті так простіше; саме так улаштований офіційний стартер):

giftgenius/
  app/
    page.tsx         # Віджет
    api/
      mcp/route.ts   # MCP endpoint
  next.config.mjs
  package.json
  ...

У лекціях Модуля 2 ви вже клонували Apps SDK Starter, встановлювали залежності й запускали npm run dev. Тепер припускаємо, що:

  • проєкт уже в Git (GitHub / GitLab / Bitbucket);
  • локально ви використовуєте .env.local з ключами (OPENAI_API_KEY та ін.);
  • ChatGPT Dev Mode підʼєднано до вашого тунелю.

Ваше завдання — зробити так, щоб цей самий код збирався й працював на Vercel, а ChatGPT звертався не до тунелю, а до стабільного HTTPS‑домену на кшталт https://giftgenius.vercel.app.

3. Підготовка репозиторію до розгортання

Перш ніж натискати у Vercel кнопку «New Project», варто трохи впорядкувати репозиторій. Кроки прості, але зекономлять вам купу часу згодом.

По‑перше, переконайтеся, що .env.local і .vercel не потрапляють у репозиторій. У .gitignore у Next.js Starter це зазвичай уже є, але краще перевірити:

node_modules
.next
.env.local
.vercel

.env.local — це ваша локальна конфігурація й секрети. Його ніколи не має бути в Git, особливо якщо там OPENAI_API_KEY або ключі до бази. На Vercel секрети зберігатимете окремо — в інтерфейсі.

По‑друге, зазирніть у package.json. Для Vercel важливі коректні scripts:

{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
  }
}

Vercel за замовчуванням запускатиме npm run build (або pnpm build, якщо ви використовуєте pnpm). Команда має збирати проєкт без помилок.

По‑третє, переконайтеся, що версію Node вказано і що вона підходить для Next.js 16. У нотатках до релізу Next.js 16 мінімальна версія — 18.18.0. Найчастіше достатньо поля в package.json:

{
  "engines": {
    "node": ">=18.18.0"
  }
}

Vercel підбере LTS‑версію Node, сумісну з вашим застосунком.

Якщо все це зроблено, можна надіслати (push) останні зміни в Git і переходити до Vercel.

4. Перший імпорт проєкту у Vercel

Тепер переходьте у вебінтерфейс Vercel. Якщо ви там ще не зареєстровані, саме час це зробити.

Ви входите у Vercel, натискаєте «New Project» і обираєте зі списку свій репозиторій giftgenius. На цьому етапі Vercel «за лаштунками» перевіряє вміст репозиторію й майже завжди сам визначає, що це Next.js‑проєкт, підставляючи відповідний пресет.

У налаштуваннях проєкту Vercel запропонує:

  • Framework = Next.js;
  • Build Command = npm run build (або pnpm build/yarn build);
  • Output Directory — стандартна .next (не потрібно змінювати).

Для першого розгортання можна не задавати env‑змінні одразу (ми додамо їх окремим кроком). Натискаєте «Deploy» — Vercel клонує репозиторій, встановлює залежності, запускає npm run build і, якщо все успішно, створює перше розгортання з адресою на кшталт https://giftgenius-xyz.vercel.app.

Важливо зрозуміти одну річ: кожне розгортання — незмінне (immutable). Якщо ви потім надсилаєте (push) зміни, створюється нове розгортання з новим URL, а старе залишається в історії. Production‑домен (наприклад, giftgenius.vercel.app або ваш кастомний домен) вказує на конкретне розгортання. За потреби його можна перемкнути назад, зробивши rollback.

Схематично це виглядає так:

flowchart LR
    A[GitHub‑репозиторій
giftgenius] -->|git push| B[Збирання Vercel] B --> C[Preview‑розгортання №1
унікальний URL] B --> D[Preview‑розгортання №2
унікальний URL] D --> E[Production‑аліас
giftgenius.vercel.app]

Git‑гілку main зазвичай вважають production‑гілкою, а все інше — preview. За потреби це можна змінити.

5. Змінні середовища на Vercel

Зараз ваше перше розгортання, найімовірніше, працює не повністю: немає OPENAI_API_KEY, MCP‑сервер не звертається до зовнішніх API тощо. Саме час зайнятися env‑змінними.

У Vercel env‑змінні зберігаються в розділі Settings → Environment Variables. Там же видно поділ на три scope: Development, Preview і Production.

Табличка для ментальної моделі:

Scope Де використовується Локальний аналог
Development vercel dev і локальний dev через Vercel CLI .env.local
Preview усі розгортання з гілок, окрім production‑гілки staging / test
Production розгортання з production‑гілки (зазвичай main) «бойовий» .env.prod

Відмінність від локального .env.local у тому, що Vercel зберігає значення зашифрованими й автоматично підставляє їх як process.env.MY_VAR у коді Next.js.

Дуже важливо розуміти префікс NEXT_PUBLIC_. Усе, що починається з NEXT_PUBLIC_, потрапить у браузерний бандл і буде видиме будь‑якому користувачу (це можна подивитися через DevTools). Це добре для публічної конфігурації (NEXT_PUBLIC_ENV=preview, NEXT_PUBLIC_API_BASE_URL=https://giftgenius.vercel.app), але категорично погано для ключів на кшталт OPENAI_API_KEY.

Для секретів використовуйте назви без NEXT_PUBLIC_ і читайте їх лише на серверному боці: у route handlers, MCP‑інструментах тощо.

6. Налаштування env для GiftGenius: приклад

Подивімося, які env‑змінні потрібні вашому навчальному GiftGenius.

Мінімальний набір може бути таким:

  • OPENAI_API_KEY — ключ для виклику моделей / MCP‑клієнта;
  • APP_BASE_URL — базовий URL застосунку (https://giftgenius.vercel.app або preview‑URL);
  • можливо, GIFTDATA_API_URL або PRODUCTS_API_URL, якщо у вас є зовнішній каталог.

У локальній розробці це лежить у .env.local:

OPENAI_API_KEY=sk-local-...
APP_BASE_URL=http://localhost:3000
PRODUCTS_API_URL=https://dev-api.gifts.example.com

На Vercel ви переходите в Settings → Environment Variables і додаєте ті самі ключі та значення, але вже до відповідних scopeʼів.

Приклад того, як це виглядає в коді MCP‑endpointʼа:

// app/api/mcp/route.ts
import { NextRequest } from 'next/server';

const apiKey = process.env.OPENAI_API_KEY!; // так робити не слід без перевірок у реальному коді :)

export async function POST(req: NextRequest) {
  if (!apiKey) {
    return new Response('Missing OPENAI_API_KEY', { status: 500 });
  }
  // Виклик OpenAI або іншого сервісу з apiKey...
}

Віджет може використовувати APP_BASE_URL на серверному боці, наприклад, щоб будувати абсолютні посилання з урахуванням ChatGPT‑iframe і конфігурації assetPrefix/basePath зі стартер‑шаблону.

Якщо йому потрібен публічний URL API (наприклад, для window.fetch до вашого бекенду), для цього можна завести NEXT_PUBLIC_API_BASE_URL. Але в жодному разі не NEXT_PUBLIC_OPENAI_API_KEY.

7. Preview‑розгортання: staging без зайвої метушні

Тепер про найприємніше — preview‑розгортання. Коли ви підʼєднали Git‑репозиторій, Vercel автоматично починає створювати preview‑розгортання для кожного push у будь‑яку гілку, крім production, або для кожного Pull Request. У кожного такого розгортання є унікальний URL, на кшталт:

https://giftgenius-git-feature-new-layout-username.vercel.app

Ці розгортання використовують scope Preview для env‑змінних, тож ви можете задати, наприклад:

# Середовище Preview на Vercel
APP_BASE_URL=https://giftgenius-staging.vercel.app
PRODUCTS_API_URL=https://staging-api.gifts.example.com

— і не плутати це з Production.

З погляду ChatGPT Dev Mode preview‑URL — ідеальний кандидат на staging. У налаштуваннях вашого Dev‑App ви можете тимчасово змінити endpoint із тунельного URL на preview‑URL і подивитися, як поводиться вже зібрана версія GiftGenius, але ще не production‑розгортання.

Поширений підхід такий: для фічі ви створюєте гілку feature/smart-recommendations, надсилаєте (push) зміни — Vercel дає preview‑посилання. Далі ви заходите в Dev Mode, змінюєте URL на це посилання, перевіряєте сценарії з GPT (підбір подарунка, відображення карток, виклики MCP‑інструментів). І лише коли все гаразд, зливаєте зміни в main. Production тим часом живе своїм спокійним життям.

Ментальна схема pipeline:

flowchart TD
    A[Локальна розробка
localhost + тунель] --> B[git push
feature/*] B --> C[Preview‑розгортання
preview‑URL] C --> D[ChatGPT Dev Mode
App → preview‑URL] C --> E[Code review / тести] E --> F[Merge у main] F --> G[Production‑розгортання
prod‑URL] G --> H[ChatGPT Prod App
App → prod‑URL]

8. Production‑розгортання і rollback

Коли ви зливаєте зміни в main (або в іншу обрану вами production‑гілку), Vercel створює production‑розгортання і «вішає» на нього production‑аліас: giftgenius.vercel.app або ваш власний домен.

У цей момент ChatGPT Prod‑App (який ви створите трохи пізніше) має бути налаштований на production‑URL. У Dev Mode ви продовжуєте експериментувати з тунелем або preview‑URL. А звичайні користувачі в ChatGPT Store звертатимуться саме до Production.

Перевага незмінних (immutable) розгортань у тому, що rollback стає дуже простим. Якщо новий реліз виявився невдалим (наприклад, MCP‑інструмент «падає» на продакшен‑даних), не потрібно терміново «гасити пожежу» в проді. Ви відкриваєте список розгортань у Vercel, обираєте попереднє успішне й натискаєте щось на кшталт «Promote to Production». Далі десь у фоновому режимі перемикаються K8s і Lambda, а ваш домен знову вказує на стабільну версію.

У CLI це теж можна автоматизувати через команду vercel rollback, але в межах нашого курсу достатньо розуміти ідею: кожне розгортання — окремий артефакт, а production‑аліас можна спрямувати на будь‑яке з них.

9. Специфіка Next.js 16 + MCP на Vercel

З погляду Vercel ваш MCP‑endpoint у Next.js — це безсерверна функція (або edge‑функція, якщо ви так налаштували). Вона живе недовго: «прокидається» за запитом, обробляє його і «помирає». Стан між викликами зберігати не можна, хіба що ви використовуєте зовнішню БД або якесь сховище.

Це критично для MCP. Якщо ви раптом вирішите складати історію діалогу в глобальний масив let history = [] у route.ts, він обнулятиметься на кожному холодному старті. Щоб зберігати стан, потрібна зовнішня система (KV, Postgres тощо), але це вже тема майбутніх модулів.

Другий аспект — тайм‑аути виконання. На безплатних планах Vercel безсерверні функції мають обмеження за часом (на момент підготовки матеріалів — приблизно 10 секунд на Hobby, більше на Pro). Для LLM‑запитів, а особливо для ланцюжків MCP‑інструментів, цього може бути замало.

У Next.js 16 для route handlers можна задавати maxDuration, щоб явно попросити у Vercel більше часу (у межах плану):

// app/api/mcp/route.ts
export const maxDuration = 60; // секунди, на Pro можна до 300

export async function POST(req: Request) {
  // довга операція: запит до OpenAI, зовнішньої БД тощо
}

Це не магічна кнопка «працюй скільки завгодно». Але це коректний спосіб сказати Vercel: «ця функція може виконуватися довше — будь ласка, не зупиняй її надто рано».

Нарешті, не забувайте про особливості ChatGPT‑iframe. У Apps SDK Starter уже налаштовані assetPrefix і basePath, щоб статика й маршрути коректно працювали всередині вкладених iframe web-sandbox.oaiusercontent.com. Завдяки цьому всі запити йдуть на ваш домен, а не на sandbox. Під час розгортання на Vercel ця конфігурація зберігається, тож ви отримуєте коректну роботу віджета одразу.

10. Інтеграція з ChatGPT після розгортання

Хоча формально це ближче до модулів про Store і продакшен, логіка інтеграції з ChatGPT після розгортання доволі проста — і добре «лягає» вже зараз.

Спочатку ви розгортаєте GiftGenius на Vercel і отримуєте production‑URL. Потім у ChatGPT у Dev Mode створюєте окремий App, наприклад GiftGenius Prod, і в його налаштуваннях як endpoint указуєте цей URL (точніше, MCP‑endpoint на кшталт https://giftgenius.vercel.app/api/mcp згідно з посібником OpenAI Apps SDK Deploy).

Для розробки ви продовжуєте використовувати Dev App, який дивиться на тунель або preview‑URL. Для тестування денних/тижневих білдів можна завести Staging‑App, привʼязавши його до постійного preview‑аліаса. У результаті виходить триступенева схема:

Dev App     → локальний тунель або dev‑URL (нестабільний)
Staging App → стабільний preview/staging URL на Vercel
Prod App    → production URL на Vercel

Для орієнтиру зведемо все в одну таблицю:

Що URL / розгортання на Vercel Scope на Vercel Хто звертається
Dev App локальний тунель / vercel dev Development ви / команда
Staging App стабільний preview‑аліас Preview команда / QA
Prod App giftgenius.vercel.app / кастомний домен Production користувачі

Це та сама модель local / staging / prod, про яку ви говорили на початку модуля, тільки тепер — із привʼязкою до Vercel і ChatGPT Apps. Це вже архітектура дорослого проєкту, а не «вічний localhost».

11. Типові помилки під час розгортання на Vercel

Помилка № 1: секрети залишилися тільки в .env.local, а на Vercel їх немає.
Дуже поширений сценарій: локально все працює, ви впевнено натискаєте «Deploy», застосунок збирається, але MCP‑інструменти в продакшені повертають 500 із текстом «Missing OPENAI_API_KEY». Причина проста: Vercel не знає про ваші локальні .env.local. Потрібно окремо додати ті самі змінні в налаштування проєкту на Vercel (і в правильні scopeʼи: Preview, Production).

Помилка № 2: використання NEXT_PUBLIC_ для чутливих даних.
Бажання «просто щоб працювало» іноді перемагає, і розробник задає NEXT_PUBLIC_OPENAI_API_KEY, щоб мати доступ до ключа з клієнтського коду. У результаті ключ опиняється в JS‑бандлі й стає доступним будь‑якому користувачу. Це не просто погана практика — це прямий шлях до витоку й блокування ключа. Усі секрети — тільки без префікса й лише на серверному боці.

Помилка № 3: невідповідність середовищ між локальною розробкою та Vercel.
Локально у вас може бути один URL для продуктів (http://localhost:4000), на Vercel — інший (https://api.gifts-staging.com), а в проді — третій. Якщо не вести акуратний список env‑змінних і не перевіряти, що в Preview/Production вони заповнені коректно, легко отримати ситуацію, коли продакшен‑віджет звертається до staging‑бекенду, а staging‑віджет — до прод. Допомагає проста дисципліна: документувати всі потрібні змінні й перевіряти їх у кожному середовищі.

Помилка № 4: ігнорування лімітів часу виконання для MCP‑endpointʼів.
Локально ви можете чекати на відповідь від якоїсь повільної зовнішньої системи 30 секунд і не помітити проблеми. На Vercel та сама функція отримає тайм‑аут через 10–15 секунд, і ChatGPT побачить помилку. Якщо ви не налаштували maxDuration і не стежите за часом роботи MCP‑інструментів, у проді це може перетворюватися на випадкові падіння.

Помилка № 5: спроба зберігати стан MCP у памʼяті безсерверної функції.
Інколи дуже хочеться покласти історію діалогу або кеш рекомендацій у глобальну змінну let cache = {} просто у файлі обробника маршруту. Локально, доки dev‑сервер довго працює, це може навіть «працювати». Але на Vercel кожна безсерверна функція живе недовго й часто створюється заново. У результаті частина запитів «бачить» старий cache, частина — новий, а частина — порожній. Це породжує дивні баги, які важко відтворити. Для стану потрібна зовнішня БД або KV‑сховище; у межах цієї лекції краще взагалі вважати MCP‑endpoint stateless.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ