CodeGym /Kursy /ChatGPT Apps /Deploy na Vercel: repozytorium, zmienne env, preview → pr...

Deploy na Vercel: repozytorium, zmienne env, preview → production

ChatGPT Apps
Poziom 7 , Lekcja 3
Dostępny

1. Po co nam Vercel dla ChatGPT App

W poprzednich wykładach uruchamialiśmy GiftGenius lokalnie i łączyliśmy go z ChatGPT przez Dev Mode i tunel. Teraz czas zrobić kolejny krok w stronę „dorosłej” produkcji i przenieść ten sam kod na Vercel.

Na tym etapie macie już działającą aplikację GiftGenius (naszą umowną aplikację szkoleniową). Lokalnie działa na Next.js 16 z MCP‑endpointem (np. /api/mcp) i jest zbudowana na bazie oficjalnego ChatGPT Apps SDK Next.js Starter.

Można by pójść drogą „wynajmę VPS, ręcznie zainstaluję Node, nginx i wszystko sam skonfiguruję”, ale dla Next.js to mniej więcej jak pisanie frontendu na czystym document.write w 2025 roku. Działa, ale zdecydowanie utrudniacie sobie życie.

Vercel jest dla nas dobry z kilku powodów.

Po pierwsze, natomiast rozumie Next.js: automatycznie konfiguruje build, SSR, statykę, warstwę edge i funkcje serverless. Dla ChatGPT App to szczególnie wygodne, bo widżet i MCP‑endpoint wdraża się jednym przyciskiem i działają w tej sameej infrastrukturze.

Po drugie, Vercel daje CI/CD out‑of‑the‑box: podłączacie repozytorium Git — i każdy push tworzy nowy immutable deployment z unikalnym URL. Z gałęzi main jest traktowany jako production, z innych gałęzi — jako preview.

Po trzecie, Vercel ma wygodny model środowisk i sekretów. Wyraźnie dzieli zmienne env na Development, Preview i Production, przechowuje je zaszyfrowane i pozwala łatwo przekazywać do Next.js. To dokładnie to, czego potrzebuje ChatGPT App, gdzie klucze i URL serwera MCP muszą się zmieniać w zależności od środowiska.

Po czwarte, Vercel oferuje wygodne rollbacki: jeśli nowy release poszedł nie tak, można szybko wypromować poprzedni udany deploy i przywrócić system do działania. To zmniejsza „strach przed deployem” i zachęca do małych, częstych wydań.

I wreszcie, Vercel to firma twórców Next.js. Dostosowali Next.js do swoich serwerów, a swoje serwery do Next.js. Korzystając z Vercel, nie raz poczujecie, jak płynnie wszystko działa — dosłownie w kilku klikach. Gwarantuję — spodoba wam się.

2. Punkt wyjścia: struktura projektu GiftGenius

Zgodnie z planem kursu nasz GiftGenius żyje w jednym repozytorium. Są dwa warianty organizacji i oba są poprawne dla Vercel:

1) Monorepo z kilkoma aplikacjami — na przykład:

giftgenius/
  apps/
    web/   # Next.js (widżet + MCP)
    mcp/   # osobny serwer MCP (jeśli go wydzieliliście)

2) Jeden projekt Next.js, w którym widżet i MCP żyją razem (to prostsze na pierwszym etapie i dokładnie tak jest zrobiony oficjalny starter):

giftgenius/
  app/
    page.tsx         # Widżet
    api/
      mcp/route.ts   # MCP endpoint
  next.config.mjs
  package.json
  ...

W wykładach modułu 2 klonowaliście już Apps SDK Starter, instalowaliście zależności i uruchamialiście npm run dev. Teraz zakładamy, że:

  • projekt jest już w Git (GitHub / GitLab / Bitbucket);
  • lokalnie używacie .env.local z kluczami (OPENAI_API_KEY i inne);
  • ChatGPT Dev Mode jest podłączony do waszego tunelu.

Naszym celem jest sprawić, aby ten sam kod budował się i działał na Vercel, a ChatGPT korzystał nie z tunelu, lecz ze stabilnej domeny HTTPS w stylu https://giftgenius.vercel.app.

3. Przygotowanie repozytorium do deployu

Zanim klikniecie w Vercel „New Project”, warto nieco uporządkować repozytorium. To proste kroki, ale później oszczędzą masę czasu.

Po pierwsze, upewnijcie się, że .env.local i .vercel nie trafiają do repozytorium. W .gitignore w Next.js Starter zwykle już to jest, ale lepiej sprawdzić:

node_modules
.next
.env.local
.vercel

.env.local to wasza lokalna konfiguracja i sekrety. Nigdy nie powinno tego być w Git, szczególnie jeśli są tam OPENAI_API_KEY lub klucze do bazy. Na Vercel będziemy trzymać sekrety osobno w UI.

Po drugie, spójrzcie na package.json. Dla Vercel ważne są poprawne scripts:

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

Domyślnie Vercel wywoła npm run build (lub pnpm build, jeśli używacie pnpm). To powinno budować projekt bez błędów.

Po trzecie, upewnijcie się, że wersja Node jest podana i pasuje do Next.js 16. W release notes Next.js 16 minimalna wersja to 18.18.0. Najczęściej wystarczy pole w package.json:

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

Vercel dobierze wersję LTS Node kompatybilną z waszą aplikacją.

Jeśli to wszystko jest zrobione, można wypchnąć najnowszy kod do Git i przejść do Vercel.

4. Pierwszy import projektu do Vercel

Przechodzimy teraz do interfejsu webowego Vercel. Jeśli jeszcze nie macie tam konta — to najwyższy czas.

Logujecie się do Vercel, klikacie „New Project” i wybieracie z listy swoje repozytorium giftgenius. Na tym etapie Vercel pod spodem sprawdza zawartość repozytorium i prawie zawsze sam rozpoznaje projekt Next.js, podstawiając odpowiedni preset.

W ustawieniach projektu Vercel zaproponuje:

  • Framework = Next.js;
  • Build Command = npm run build (lub pnpm build/yarn build);
  • Output Directory — standardowe .next (nie trzeba zmieniać).

Do pierwszego deployu nie trzeba od razu podawać zmiennych env (dodamy je osobnym krokiem). Klikacie „Deploy” — Vercel klonuje repozytorium, instaluje zależności, uruchamia npm run build i, jeśli wszystko się powiedzie, tworzy pierwszy deploy z adresem w rodzaju https://giftgenius-xyz.vercel.app.

Ważna rzecz: każdy deploy jest immutable. Gdy później wypchnięcie zmiany, powstaje nowy deploy z nowym URL, a stary zostaje w historii. Domena produkcyjna (np. giftgenius.vercel.app lub wasza własna) wskazuje na konkretny deploy i można ją przełączyć z powrotem, robiąc rollback.

Schematycznie wygląda to tak:

flowchart LR
    A[Repozytorium GitHub
giftgenius] -->|git push| B[Build w Vercel] B --> C[Preview Deploy #1
unikalny URL] B --> D[Preview Deploy #2
unikalny URL] D --> E[Alias produkcyjny
giftgenius.vercel.app]

Gałąź Git main zwykle jest traktowana jako production, wszystko pozostałe — jako preview. Można to jednak przestawić.

5. Zmienne środowiskowe na Vercel

Wasz pierwszy deploy prawdopodobnie niewiele działa: brak OPENAI_API_KEY, serwer MCP nie woła zewnętrznych API itp. Czas zająć się zmiennymi env.

W Vercel zmienne env znajdują się w Settings → Environment Variables. Tam też widać podział na trzy scope’y: Development, Preview i Production.

Tabela dla modelu mentalnego:

Scope Gdzie używane Odpowiednik lokalnie
Development vercel dev i lokalny dev przez Vercel CLI .env.local
Preview wszystkie deploye z gałęzi innych niż produkcyjna staging / test
Production deploye z gałęzi produkcyjnej (zwykle main) „produkcyjny” .env.prod

Różnica względem lokalnego .env.local polega na tym, że Vercel przechowuje wartości zaszyfrowane i automatycznie podstawia je jako process.env.MY_VAR w kodzie Next.js.

Bardzo ważny jest prefiks NEXT_PUBLIC_. Wszystko, co zaczyna się od NEXT_PUBLIC_, trafi do bundla przeglądarkowego i będzie widoczne dla każdego użytkownika (można to podejrzeć w DevTools). To dobre dla publicznej konfiguracji (NEXT_PUBLIC_ENV=preview, NEXT_PUBLIC_API_BASE_URL=https://giftgenius.vercel.app), ale kategorycznie złe dla kluczy takich jak OPENAI_API_KEY.

Dla sekretów używamy nazw bez NEXT_PUBLIC_ i czytamy je wyłącznie po stronie serwera: w route handlers, narzędziach MCP itd.

6. Konfiguracja env dla GiftGenius: przykład

Zobaczmy, jakie zmienne env są potrzebne naszej szkoleniowej aplikacji GiftGenius.

Minimalny zestaw może wyglądać tak:

  • OPENAI_API_KEY — klucz do wywoływania modeli / klienta MCP;
  • APP_BASE_URL — bazowy URL aplikacji (https://giftgenius.vercel.app lub adres preview);
  • ewentualnie GIFTDATA_API_URL lub PRODUCTS_API_URL, jeśli macie zewnętrzny katalog.

W lokalnym developmentcie leży to w .env.local:

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

Na Vercel wchodzicie w Settings → Environment Variables i dodajecie te same klucze i wartości, już w odpowiednich scope’ach.

Przykład, jak to wygląda w kodzie MCP‑endpointu:

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

const apiKey = process.env.OPENAI_API_KEY!; // nie róbcie tak bez sprawdzeń w prawdziwym kodzie :)

export async function POST(req: NextRequest) {
  if (!apiKey) {
    return new Response('Missing OPENAI_API_KEY', { status: 500 });
  }
  // Wywołanie OpenAI lub innej usługi z apiKey...
}

Widżet może używać APP_BASE_URL po stronie serwera, np. aby budować linki absolutne, z uwzględnieniem ChatGPT‑iframe oraz konfiguracji assetPrefix/basePath ze startera.

Jeśli potrzebny jest publiczny URL API (np. do window.fetch na wasz backend), można utworzyć NEXT_PUBLIC_API_BASE_URL. Ale pod żadnym pozorem nie NEXT_PUBLIC_OPENAI_API_KEY.

7. Preview‑deploye: staging na sterydach

Teraz o najprzyjemniejszym: preview‑deployach. Po podłączeniu repozytorium Git Vercel automatycznie tworzy preview‑deploy dla każdego pushu do gałęzi innej niż produkcyjna lub dla każdego Pull Request. Każdy taki deploy ma unikalny URL, np.:

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

Te deploye używają scope Preview dla zmiennych env, więc możecie ustawić np.:

# Preview env na Vercel
APP_BASE_URL=https://giftgenius-staging.vercel.app
PRODUCTS_API_URL=https://staging-api.gifts.example.com

i nie mylić tego z production.

Z punktu widzenia ChatGPT Dev Mode URL preview to idealny kandydat na staging. W ustawieniach waszego Dev‑App możecie tymczasowo zmienić endpoint z tunelowego URL na URL preview i zobaczyć, jak zachowuje się już zbudowana wersja GiftGenius, ale jeszcze nieprodukcyjny deploy.

Częsty schemat: dla funkcji tworzycie gałąź feature/smart-recommendations, wypychacie zmiany — Vercel daje link preview. Wchodzicie w Dev Mode, zmieniacie URL na ten link, sprawdzacie scenariusze z GPT (dobór prezentu, wyświetlanie kart, wywołania narzędzi MCP). Dopiero gdy wszystko jest OK, mergujecie do main. Production w tym czasie żyje własnym, spokojnym życiem.

Schemat pipeline’u:

flowchart TD
    A[Lokalny dev
localhost + tunel] --> B[git push
feature/*] B --> C[Preview Deploy
preview‑URL] C --> D[ChatGPT Dev Mode
App → preview‑URL] C --> E[Code review / testy] E --> F[Merge do main] F --> G[Production Deploy
prod‑URL] G --> H[ChatGPT Prod App
App → prod‑URL]

8. Production‑deploy i rollback

Gdy mergujecie zmiany do main (lub innej wybranej gałęzi produkcyjnej), Vercel tworzy production‑deploy i podłącza do niego production‑alias: giftgenius.vercel.app lub waszą własną domenę.

W tym momencie ChatGPT Prod‑App (który utworzycie nieco później) powinien być skonfigurowany na URL produkcyjny. W Dev Mode nadal eksperymentujecie z tunelem albo URL preview; zwykli użytkownicy w ChatGPT Store będą trafiać właśnie do production.

Zaletą immutable‑deployów jest to, że rollback jest bardzo prosty. Jeśli nowy release okazał się nieudany (np. narzędzie MCP sypie się na danych produkcyjnych), nie trzeba na gwałt naprawiać na produkcji. Otwieracie listę deployów w Vercel, wybieracie poprzedni udany i klikacie coś w rodzaju „Promote to Production” — gdzieś daleko K8s i Lambda się przełączają, a wasza domena znów wskazuje stabilną wersję.

W CLI można to też zautomatyzować komendami vercel rollback, ale na potrzeby tego kursu wystarczy zrozumieć ideę: każdy deploy to osobny artefakt, a production‑alias można skierować na dowolny z nich.

9. Specyfika Next.js 16 + MCP na Vercel

Z punktu widzenia Vercel wasz MCP‑endpoint w Next.js to funkcja serverless (lub funkcja edge, jeśli tak ją ustawiliście). Żyje krótko: budzi się na żądanie, obsługuje je i umiera. Nie można przechowywać stanu między wywołaniami, chyba że używacie zewnętrznej bazy danych lub innego magazynu.

To krytyczne dla MCP: jeśli zechcecie zapisywać historię dialogu w globalnej tablicy let history = [] w route.ts, będzie się zerować przy każdym zimnym starcie. Do przechowywania stanu trzeba użyć systemu zewnętrznego (KV, Postgres itd.), ale to temat przyszłych modułów.

Drugi aspekt to limity czasu wykonywania. W darmowych planach Vercel funkcje serverless mają ograniczenie czasu (w momencie przygotowania materiałów — około 10 sekund w planie Hobby, więcej w Pro). Dla zapytań LLM, a zwłaszcza łańcuchów narzędzi MCP, może to być mało.

W Next.js 16 dla route handlers można ustawiać maxDuration, aby wyraźnie poprosić Vercel o więcej czasu (w granicach planu):

// app/api/mcp/route.ts
export const maxDuration = 60; // sekundy, w Pro można do 300

export async function POST(req: Request) {
  // długa operacja: zapytanie do OpenAI, zewnętrznej bazy itd.
}

To nie jest magiczny przycisk „działaj ile chcesz”, ale poprawny sposób powiedzenia Vercel: „ta funkcja może działać dłużej, proszę nie ubijaj jej zbyt szybko”.

Na koniec pamiętajcie o specyfice ChatGPT‑iframe. W Apps SDK Starter są już skonfigurowane assetPrefix i basePath, aby statyki i trasy poprawnie działały wewnątrz zagnieżdżonych iframe’ów web-sandbox.oaiusercontent.com. Dzięki temu wszystkie żądania idą na waszą domenę, a nie do sandboxa. Po deployu na Vercel ta konfiguracja zostaje, więc dostajecie poprawnie działający widżet prosto z pudełka.

10. Integracja z ChatGPT po deployu

Choć formalnie to bliżej modułów o Store i produkcji, żywot aplikacji i logika integracji z ChatGPT po deployu są dość proste i dobrze „wchodzą” już teraz.

Najpierw deployujecie GiftGenius na Vercel i otrzymujecie URL produkcyjny. Potem w ChatGPT, w Dev Mode, tworzycie osobny App, np. GiftGenius Prod, i w jego ustawieniach jako endpoint podajecie ten URL (ściślej, MCP‑endpoint w rodzaju https://giftgenius.vercel.app/api/mcp, zgodnie z przewodnikiem OpenAI Apps SDK Deploy).

Do developmentu nadal używacie Dev App, skierowanego na tunel lub URL preview. Do testowania dziennych/tygodniowych buildów możecie stworzyć Staging‑App, podpinając go do stałego aliasu preview. W efekcie powstaje trzystopniowy układ:

Dev App     → lokalny tunel lub dev‑URL (niestabilny)
Staging App → stabilny preview/staging URL na Vercel
Prod App    → production URL na Vercel

Dla orientacji zbierzmy wszystko w jedną tabelę:

Co URL / deploy na Vercel Scope na Vercel Kto korzysta
Dev App lokalny tunel / vercel dev Development wy / zespół
Staging App stały alias preview Preview zespół / QA
Prod App giftgenius.vercel.app / własna domena Production użytkownicy

To ten sam model local / staging / prod, o którym mówiliśmy na początku modułu, tylko teraz z powiązaniem do Vercel i ChatGPT Apps. To już architektura dojrzałego projektu, a nie wieczny localhost.

11. Typowe błędy przy deployu na Vercel

Błąd nr 1: sekrety zostały tylko w .env.local, a na Vercel ich nie ma.
Bardzo częsty scenariusz: lokalnie wszystko działa, pewnie klikacie „Deploy”, aplikacja się buduje, ale narzędzia MCP na produkcji zwracają 500 z treścią „Missing OPENAI_API_KEY”. Powód jest prosty: Vercel nie zna waszego lokalnego .env.local. Trzeba osobno wprowadzić te same zmienne w ustawieniach projektu na Vercel (i w odpowiednich scope’ach: Preview, Production).

Błąd nr 2: użycie NEXT_PUBLIC_ dla wrażliwych danych.
Czasem wygrywa chęć „byle działało” i ktoś wpisuje NEXT_PUBLIC_OPENAI_API_KEY, by mieć dostęp do klucza w kodzie klienckim. W efekcie klucz ląduje w bundlu JS i jest dostępny dla każdego. To nie tylko zła praktyka — to prosta droga do wycieku i zablokowania klucza. Wszystkie sekrety — tylko bez prefiksu i tylko po stronie serwera.

Błąd nr 3: niespójność środowisk między lokalnym a Vercel.
Lokalnie możecie mieć jeden URL produktów (http://localhost:4000), na Vercel — inny (https://api.gifts-staging.com), a na produkcji — trzeci. Jeśli nie prowadzicie dokładnej listy zmiennych env i nie sprawdzacie, czy w Preview/Production są poprawnie wypełnione, łatwo o sytuację, w której widżet produkcyjny trafia na backend staging, a stagingowy — na produkcję. Pomaga prosta dyscyplina: dokumentować potrzebne zmienne i sprawdzać je na każdym środowisku.

Błąd nr 4: ignorowanie limitów czasu wykonania dla endpointów MCP.
Lokalnie możecie czekać na odpowiedź od jakiegoś wolnego systemu zewnętrznego 30 sekund i nie zauważyć problemów. Na Vercel ta sama funkcja dostanie timeout po 10–15 sekundach i ChatGPT zobaczy błąd. Jeśli nie ustawicie maxDuration i nie kontrolujecie czasu pracy narzędzi MCP, na produkcji może to powodować losowe awarie.

Błąd nr 5: próba trzymania stanu MCP w pamięci funkcji serverless.
Czasem bardzo kusi, by wrzucić historię dialogu lub cache rekomendacji do globalnej zmiennej let cache = {} w pliku route handlera. Lokalnie, dopóki dev‑serwer działa długo, może to nawet „działać”. Ale na Vercel każda funkcja serverless żyje krótko i często jest tworzona na nowo. W efekcie część żądań „widzi” stary cache, część — nowy, a część — pusty. To rodzi dziwne bugi, które trudno odtworzyć. Do stanu potrzebna jest zewnętrzna baza lub KV‑magazyn; na poziomie tego wykładu najlepiej przyjąć, że MCP‑endpoint jest stateless.

Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION