1. Por qué necesitamos Vercel para ChatGPT App
En las lecciones anteriores, ejecutamos GiftGenius en local y lo conectamos a ChatGPT mediante Dev Mode y un túnel. Ahora toca dar otro paso hacia una producción «seria» y llevar ese mismo código a Vercel.
A estas alturas ya tienes una aplicación funcional, GiftGenius (nuestro App didáctico). En local corre con Next.js 16 con un endpoint MCP (por ejemplo, /api/mcp) y está basado en el ChatGPT Apps SDK Next.js Starter oficial.
Podrías seguir el camino de «alquilo un VPS, instalo Node, nginx y lo configuro todo a mano», pero para Next.js eso es como escribir frontend con document.write en pleno 2025. Funciona, pero te complicas la vida innecesariamente.
Vercel es bueno para nosotros por varias razones.
En primer lugar, entiende Next.js de forma nativa: configura automáticamente la build, SSR, estáticos, capa edge y funciones serverless. Para un ChatGPT App esto es especialmente cómodo, porque el widget y el endpoint MCP se despliegan con un clic y viven en la misma infraestructura.
En segundo lugar, Vercel ofrece CI/CD de serie: conectas tu repositorio Git y cada push crea un despliegue inmutable con una URL única. Desde la rama main se considera producción; desde las demás, preview.
En tercer lugar, Vercel tiene muy buen soporte de entornos y secretos. Divide explícitamente las variables env en Development, Preview y Production, las guarda cifradas y permite inyectarlas cómodamente en Next.js. Es justo lo que necesita un ChatGPT App, donde las claves y la URL del servidor MCP deben variar según el entorno.
En cuarto lugar, Vercel ofrece rollbacks cómodos: si un nuevo release sale mal, puedes promover rápidamente el despliegue anterior exitoso y devolver el sistema a un estado operativo. Esto reduce el «miedo al despliegue» y fomenta lanzamientos pequeños y frecuentes.
Y, por último, Vercel es la empresa creadora de Next.js. Han adaptado Next.js a sus servidores, y sus servidores a Next.js. Usando Vercel notarás más de una vez lo fluido que va todo y cómo funciona en un par de clics. Te garantizo que te gustará.
2. Punto de partida: estructura del proyecto GiftGenius
Según el plan del curso, nuestro GiftGenius vive en un único repositorio. Hay dos formas de organizarlo, y ambas son válidas para Vercel:
1) Monorepo con varias aplicaciones — por ejemplo:
giftgenius/
apps/
web/ # Next.js (widget + MCP)
mcp/ # servidor MCP separado (si lo separaste)
2) Un proyecto Next.js, donde el widget y MCP conviven (esto es más sencillo al principio y es justo como está el starter oficial):
giftgenius/
app/
page.tsx # Widget
api/
mcp/route.ts # endpoint MCP
next.config.mjs
package.json
...
En las lecciones del Módulo 2 ya clonaste el Apps SDK Starter, instalaste dependencias y ejecutaste npm run dev. Ahora asumimos que:
- el proyecto ya está en Git (GitHub / GitLab / Bitbucket);
- en local usas .env.local con claves (OPENAI_API_KEY y otras);
- ChatGPT Dev Mode está conectado a tu túnel.
Nuestro objetivo es lograr que ese mismo código se construya y funcione en Vercel, y que ChatGPT no vaya al túnel sino a un dominio HTTPS estable del tipo https://giftgenius.vercel.app.
3. Preparar el repositorio para el despliegue
Antes de pulsar en Vercel el botón «New Project», conviene poner un poco en orden el repositorio. Son pasos sencillos, pero ahorran mucho tiempo más adelante.
Primero, asegúrate de que .env.local y .vercel no se suben al repositorio. En el .gitignore del Starter de Next.js esto suele estar ya, pero mejor comprobarlo:
node_modules
.next
.env.local
.vercel
.env.local es tu configuración local y secretos. Nunca debe estar en Git, especialmente si contiene OPENAI_API_KEY o claves de base de datos. En Vercel guardaremos los secretos aparte en la UI.
Segundo, revisa package.json. Para Vercel son importantes los scripts correctos:
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
}
}
Vercel por defecto ejecutará npm run build (o pnpm build, si usas pnpm). Esto debe construir el proyecto sin errores.
Tercero, asegúrate de que la versión de Node está indicada y es compatible con Next.js 16. En las notas de release de Next.js 16 la versión mínima es 18.18.0. Normalmente basta con este campo en package.json:
{
"engines": {
"node": ">=18.18.0"
}
}
Vercel elegirá una versión LTS de Node compatible con tu aplicación.
Si todo esto está listo, puedes hacer push del último código a Git y pasar a Vercel.
4. Primer import del proyecto en Vercel
Ahora ve al interfaz web de Vercel. Si aún no te has registrado allí, es el momento.
Inicias sesión en Vercel, pulsas «New Project» y eliges de la lista tu repositorio giftgenius. En este paso, Vercel comprueba el contenido del repositorio y casi siempre detecta por sí mismo que es un proyecto Next.js, aplicando el preset correspondiente.
En los ajustes del proyecto Vercel propondrá:
- Framework = Next.js;
- Build Command = npm run build (o pnpm build/yarn build);
- Output Directory — la estándar .next (no hay que cambiarla).
Para el primer despliegue puedes no indicar variables env de inmediato (las añadiremos en un paso aparte). Pulsas «Deploy»: Vercel clona el repositorio, instala dependencias, ejecuta npm run build y, si todo va bien, crea el primer despliegue con una URL del estilo https://giftgenius-xyz.vercel.app.
Es importante entender algo: cada despliegue es inmutable. Si luego haces push de cambios, se crea un nuevo despliegue con nueva URL, y el anterior queda en el histórico. El dominio de producción (por ejemplo, giftgenius.vercel.app o tu dominio personalizado) apunta a un despliegue concreto, y puedes redirigirlo hacia atrás haciendo rollback.
Esquemáticamente luce así:
flowchart LR
A[Repositorio GitHub
giftgenius] -->|git push| B[Build en Vercel]
B --> C[Despliegue de preview #1
URL única]
B --> D[Despliegue de preview #2
URL única]
D --> E[Alias de producción
giftgenius.vercel.app]
La rama de Git main suele considerarse la rama de producción; todo lo demás es preview. Pero esto se puede reconfigurar.
5. Variables de entorno en Vercel
Ahora mismo tu primer despliegue probablemente no funcione del todo: falta OPENAI_API_KEY, el servidor MCP no accede a APIs externas, etc. Es hora de ocuparse de las variables de entorno.
En Vercel las variables env se guardan en Settings → Environment Variables. Ahí también se ve la separación en tres scopes: Development, Preview y Production.
Tabla para el modelo mental:
| Scope | Dónde se usa | Equivalente en local |
|---|---|---|
| Development | vercel dev y desarrollo local vía Vercel CLI | .env.local |
| Preview | todos los despliegues desde ramas que no sean la de producción | staging / test |
| Production | despliegues desde la rama de producción (normalmente main) | .env.prod «de batalla» |
A diferencia del .env.local local, Vercel guarda los valores cifrados y los inyecta automáticamente como process.env.MY_VAR en el código de Next.js.
Es crucial entender el prefijo NEXT_PUBLIC_. Todo lo que empiece por NEXT_PUBLIC_ acabará en el bundle del navegador y será visible para cualquier usuario (se puede ver por DevTools). Es bueno para configuración pública (NEXT_PUBLIC_ENV=preview, NEXT_PUBLIC_API_BASE_URL=https://giftgenius.vercel.app), pero es pésimo para claves como OPENAI_API_KEY.
Para secretos usamos nombres sin NEXT_PUBLIC_ y los leemos solo en el lado servidor: en route handlers, herramientas MCP, etc.
6. Configurar env para GiftGenius: ejemplo
Veamos qué variables env necesita nuestro GiftGenius de ejemplo.
El conjunto mínimo puede ser así:
- OPENAI_API_KEY — clave para llamadas a modelos / cliente MCP;
- APP_BASE_URL — URL base de la aplicación (https://giftgenius.vercel.app o una URL de preview);
- quizá GIFTDATA_API_URL o PRODUCTS_API_URL, si tienes un catálogo externo.
En desarrollo local esto está en .env.local:
OPENAI_API_KEY=sk-local-...
APP_BASE_URL=http://localhost:3000
PRODUCTS_API_URL=https://dev-api.gifts.example.com
En Vercel vas a Settings → Environment Variables y añades las mismas claves y valores, pero ya en los scopes correspondientes.
Ejemplo de cómo se ve en el código del endpoint MCP:
// app/api/mcp/route.ts
import { NextRequest } from 'next/server';
const apiKey = process.env.OPENAI_API_KEY!; // no hagas esto sin comprobaciones en código real :)
export async function POST(req: NextRequest) {
if (!apiKey) {
return new Response('Missing OPENAI_API_KEY', { status: 500 });
}
// Llamada a OpenAI u otro servicio con apiKey...
}
El widget puede usar APP_BASE_URL en el lado servidor, por ejemplo, para construir enlaces absolutos teniendo en cuenta el iframe de ChatGPT y la configuración de assetPrefix/basePath del starter.
Si necesita una URL pública del API (por ejemplo, para window.fetch a tu backend), puedes crear NEXT_PUBLIC_API_BASE_URL. Pero en ningún caso NEXT_PUBLIC_OPENAI_API_KEY.
7. Despliegues de preview: staging con esteroides
Vamos con lo más agradable: los despliegues de preview. Cuando conectas el repositorio Git, Vercel crea automáticamente un despliegue de preview para cada push a una rama que no sea la de producción o para cada Pull Request. Cada despliegue tiene una URL única, por ejemplo:
https://giftgenius-git-feature-new-layout-username.vercel.app
Estos despliegues usan el scope Preview para las variables env, de modo que puedes definir, por ejemplo:
# Entorno Preview en Vercel
APP_BASE_URL=https://giftgenius-staging.vercel.app
PRODUCTS_API_URL=https://staging-api.gifts.example.com
y no confundirlo con producción.
Desde el punto de vista de ChatGPT Dev Mode, la URL de preview es un candidato ideal a staging. En la configuración de tu App de desarrollo puedes cambiar temporalmente el endpoint desde la URL del túnel a la URL de preview y ver cómo se comporta la versión ya construida de GiftGenius, aunque aún no sea el despliegue de producción.
Patrón habitual: para una funcionalidad creas la rama feature/smart-recommendations, haces push de los cambios y Vercel te da un enlace de preview. Vas al Dev Mode, cambias la URL por ese enlace, verificas los escenarios con GPT (selección de regalos, visualización de tarjetas, llamadas a herramientas MCP). Solo cuando todo está OK, haces merge en main. Producción sigue su vida tranquila.
Esquema mental del pipeline:
flowchart TD
A[Desarrollo local
localhost + túnel] --> B[git push
feature/*]
B --> C[Despliegue de preview
URL de preview]
C --> D[ChatGPT Dev Mode
App → URL de preview]
C --> E[Revisión de código / pruebas]
E --> F[Merge en main]
F --> G[Despliegue de producción
URL de prod]
G --> H[ChatGPT Prod App
App → URL de prod]
8. Despliegue a producción y rollback
Cuando haces merge de cambios en main (u otra rama que elijas como de producción), Vercel crea un despliegue de producción y le asigna el alias de producción: giftgenius.vercel.app o tu dominio propio.
En ese momento, el ChatGPT Prod App (que crearás un poco más adelante) debe estar configurado con la URL de producción. En Dev Mode sigues experimentando con el túnel o con la URL de preview; los usuarios en la Store de ChatGPT irán a producción.
La ventaja de los despliegues inmutables es que el rollback es muy sencillo. Si el nuevo release es problemático (por ejemplo, una herramienta MCP falla con datos reales), no tienes que arreglarlo a toda prisa en prod. Abres la lista de despliegues en Vercel, eliges el anterior exitoso y pulsas algo como «Promote to Production»: en algún lugar K8s y Lambda se reconfiguran y tu dominio vuelve a apuntar a la versión estable.
En la CLI también puedes automatizarlo con comandos como vercel rollback, pero, a nuestro nivel, basta con entender la idea: cada despliegue es un artefacto independiente y el alias de producción puede apuntar a cualquiera de ellos.
9. Particularidades de Next.js 16 + MCP en Vercel
Para Vercel, tu endpoint MCP en Next.js es una función serverless (o una función edge, si la configuras así). Vive poco: se despierta con la petición, la atiende y se apaga. No se puede mantener estado entre invocaciones, salvo que uses una base de datos externa u otro almacén.
Esto es crítico para MCP: si decides guardar el historial del diálogo en un array global let history = [] en route.ts, se reiniciará en cada cold start. Para mantener estado hay que usar un sistema externo (KV, Postgres, etc.), pero eso lo veremos en módulos futuros.
Segundo aspecto: los tiempos de espera. En los planes gratuitos de Vercel, las funciones serverless tienen límites de tiempo (en el momento de preparar este material, en torno a 10 segundos en Hobby; más en Pro). Para peticiones a LLM y especialmente para cadenas de herramientas MCP puede ser poco.
En Next.js 16 puedes definir maxDuration en route handlers para pedir a Vercel más tiempo (dentro de los límites del plan):
// app/api/mcp/route.ts
export const maxDuration = 60; // segundos; en Pro se puede hasta 300
export async function POST(req: Request) {
// operación larga: llamada a OpenAI, a una BD externa, etc.
}
No es un botón mágico de «hazlo indefinido», pero sí la forma correcta de decirle a Vercel: «esta función puede tardar más; por favor, no la mates demasiado pronto».
Por último, no olvides las particularidades del iframe de ChatGPT. En el Apps SDK Starter ya están configurados assetPrefix y basePath para que los estáticos y rutas funcionen correctamente dentro de los iframes anidados de web-sandbox.oaiusercontent.com. Gracias a ello, todas las peticiones van a tu dominio y no al sandbox. Al desplegar en Vercel, esta configuración se mantiene, de modo que el widget funciona correctamente desde el primer momento.
10. Integración con ChatGPT tras el despliegue
Aunque formalmente esto encaja más en los módulos sobre Store y producción, la vida de la aplicación y la lógica de integración con ChatGPT tras el despliegue son bastante simples y encajan bien ya ahora.
Primero despliegas GiftGenius en Vercel y obtienes la URL de producción. Después, en ChatGPT, en Dev Mode, creas una App aparte, por ejemplo GiftGenius Prod, y en su configuración como endpoint indicas esa URL (más exactamente, el endpoint MCP tipo https://giftgenius.vercel.app/api/mcp según la guía de OpenAI Apps SDK Deploy).
Para el desarrollo sigues usando la App de Dev, apuntando al túnel o a la URL de preview. Para probar builds diarios/semanales puedes crear una App de Staging, vinculándola a un alias de preview estable. El resultado es un esquema en tres niveles:
Dev App → túnel local o dev-URL (inestable)
Staging App → URL de preview/staging estable en Vercel
Prod App → URL de producción en Vercel
Como referencia, resumimos todo en una tabla:
| Qué | URL / despliegue en Vercel | Scope en Vercel | Quién accede |
|---|---|---|---|
| Dev App | túnel local / vercel dev | Development | tú / equipo |
| Staging App | alias de preview estable | Preview | equipo / QA |
| Prod App | giftgenius.vercel.app / dominio personalizado | Production | usuarios |
Es el mismo modelo local / staging / prod del que hablamos al inicio del módulo, ahora atado a Vercel y a ChatGPT Apps. Esto ya es la arquitectura de un proyecto maduro, no un localhost eterno.
11. Errores típicos al desplegar en Vercel
Error n.º 1: los secretos se quedaron solo en .env.local y no existen en Vercel.
Escenario muy común: en local todo funciona, pulsas «Deploy» confiado, la app se construye, pero las herramientas MCP en producción devuelven 500 con el texto «Missing OPENAI_API_KEY». La razón es simple: Vercel no conoce tu .env.local local. Debes introducir por separado esas mismas variables en la configuración del proyecto en Vercel (y en los scopes adecuados: Preview, Production).
Error n.º 2: usar NEXT_PUBLIC_ para datos sensibles.
A veces gana las ganas de «que funcione ya», y el desarrollador define NEXT_PUBLIC_OPENAI_API_KEY para acceder a la clave desde código cliente. El resultado: la clave termina en el bundle JS y está al alcance de cualquier usuario. No es solo una mala práctica; es una vía directa a la filtración y el bloqueo de la clave. Todos los secretos, sin prefijo y solo en el lado servidor.
Error n.º 3: entornos incongruentes entre local y Vercel.
En local puedes tener una URL para productos (http://localhost:4000), en Vercel otra (https://api.gifts-staging.com) y en prod una tercera. Si no mantienes una lista cuidadosa de variables env y no compruebas que en Preview/Production están correctas, es fácil acabar con el widget de producción llamando al backend de staging y el de staging llamando a prod. Ayuda la disciplina simple: documentar todas las variables necesarias y revisarlas en cada entorno.
Error n.º 4: ignorar los límites de tiempo de ejecución para endpoints MCP.
En local puedes esperar la respuesta de un sistema externo lento 30 segundos y no notar problemas. En Vercel, la misma función recibirá un timeout a los 10–15 segundos, y ChatGPT verá un error. Si no ajustas maxDuration y no controlas el tiempo de ejecución de las herramientas MCP, en producción puede convertirse en caídas aleatorias.
Error n.º 5: intentar guardar el estado de MCP en memoria de la función serverless.
A veces apetece guardar el historial del diálogo o un caché de recomendaciones en una variable global let cache = {} directamente en el archivo del route handler. En local, mientras el servidor dev vive mucho, puede incluso «funcionar». Pero en Vercel cada función serverless vive poco y se recrea a menudo. El resultado: algunas peticiones «ven» un cache antiguo, otras uno nuevo y otras ninguno. Esto genera bugs extraños y difíciles de reproducir. Para estado necesitas una BD externa o un KV; al nivel de esta lección, asume el endpoint MCP como stateless.
GO TO FULL VERSION