Desplegar un agente IA en Vercel Functions: guía práctica
Resumen
Tutorial paso a paso para correr un agente de IA en Vercel: Route Handler con maxDuration, Cron Jobs con CRON_SECRET, límites Hobby vs Pro (300s / 800s / 30 min beta) y cuándo Functions alcanza frente a Workers, Railway o un VPS.

Qué resuelve
Esta pieza se queda en la decisión práctica: qué instalar, qué riesgo agrega y cómo aplicarlo sin romper operación.
La comparativa Vercel vs Workers vs VPS te dice dónde. Esta guía es el cómo cuando eliges Vercel Functions: un Route Handler con maxDuration, un cron en vercel.json y secretos por entorno. Para un agente de webhook o un job diario, Functions cubre el caso sin servidor que mantener. Las fuentes oficiales fueron consultadas el 3 de septiembre de 2026.
Si necesitas un proceso vivo con sqlite, ve a Railway o al VPS con Docker. Si el cobro por CPU del borde te conviene más, Workers. Aquí el foco es Functions.
Cuándo sí y cuándo no
Sí, si el agente:
- Vive en un repo Next.js que ya despliegas en Vercel.
- Responde webhooks y puede terminar en minutos, no en horas.
- Corre un cron diario (Hobby) o por minuto (Pro).
No, si el agente:
- Mantiene estado en RAM entre requests: cada invocación arranca de cero.
- Ejecuta un sandbox de código pesado: mejor sandboxing dedicado fuera de la Function.
- Necesita un job más frecuente que una vez al día en Hobby: el plan limita crons a una vez al día, con precisión de ±59 minutos.
La regla: Functions es un request con techo de tiempo, no un daemon.
Límites que sí importan
| Concepto | Hobby | Pro |
|---|---|---|
| Duración default | 300 s (5 min) | 300 s |
| Máximo | 300 s | 800 s (GA); 1800 s / 30 min en beta |
| Cron jobs | 100, una vez al día, precisión ±59 min | 100, hasta una vez por minuto |
| Cómo se configura >800 s | no aplica | por función (maxDuration o vercel.json), no a nivel de proyecto |
En App Router:
export const maxDuration = 300;
En Pro, 800 es el techo GA. 1800 está en beta y hay que ponerlo en cada función: un default de proyecto por encima de 800 s no está soportado todavía.
Paso 1 — Route Handler del webhook

// app/api/agente/route.ts
export const maxDuration = 300;
export async function POST(request: Request) {
const event = await request.json();
const result = await runAgent(event);
return Response.json({ ok: true, result });
}
export function GET() {
return new Response("ok", { status: 200 });
}
El webhook espera la respuesta. Si el LLM tarda 40 s, la Function sigue viva: no hay el modelo de 10 ms de CPU de Workers. El techo es el maxDuration. Si el proveedor del webhook corta a 10 s, responde 202 y mueve el trabajo a un cron o a una cola — no alargues la Function esperando un cliente que ya se fue.
Paso 2 — Cron Jobs
En Hobby el cron corre una vez al día. En Pro, hasta una vez por minuto. Se declara en vercel.json:
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"crons": [{ "path": "/api/agente/digest", "schedule": "0 14 * * *" }]
}
Vercel invoca el path con GET. Protege el endpoint con CRON_SECRET: crea la env var (mínimo 16 caracteres aleatorios) y Vercel la manda como header Authorization. Compara los dos valores antes de correr el digest. El header x-vercel-cron-schedule trae la expresión que disparó la invocación — útil si varios crons apuntan al mismo path.
Cambia el schedule, redespliega. Borrar la entrada y redesplegar elimina el cron. Desactivar sin borrar: el dashboard tiene un toggle.
Paso 3 — Secretos por entorno
Las API keys van en Environment Variables del proyecto, marcadas Sensitive, distintas para Production / Preview / Development. vercel env pull las baja a local. No las prefijes NEXT_PUBLIC_. El detalle de rotación y exposición está en secretos y variables de entorno.
Paso 4 — Deploy y verificar
pnpm dlx vercel --prod
curl -s https://tu-proyecto.vercel.app/api/agente
Criterio de éxito: el GET responde ok, un POST de prueba aparece en Runtime Logs, y el cron figura en Settings → Cron Jobs. El primer disparo en Hobby puede caer en cualquier minuto de esa hora (±59 min): no lo uses para un job a las 14:00:00 exactas.
Errores comunes

| Síntoma | Causa típica | Fix |
|---|---|---|
| Function timeout a los 300 s | Hobby no pasa de 5 min; Pro sin maxDuration | Sube de plan o baja el trabajo; en Pro pon export const maxDuration = 800 |
| Cron no corre cada hora en Hobby | Hobby es una vez al día | Sube a Pro o mueve el job a Workers |
| 401 / digest vacío | Falta CRON_SECRET o no comparas Authorization | Crea la env var y valida el header |
| Preview gasta la API key de prod | Variable no separada por entorno | Production ≠ Preview en el dashboard |
maxDuration = 1800 ignorado a nivel proyecto | Solo por función, y en beta | Decláralo en el Route Handler, no como default global |
Relación con el resto del stack
- Decidir plataforma: Vercel vs Workers vs VPS.
- Borde cobrado por CPU y cron de 15 min: Workers.
- Proceso con volumen: Railway.
- Tests antes de Production: CI/CD.
Functions + Workers juntos funciona si el Worker es la puerta (2xx rápido) y la Function hace el trabajo con maxDuration. No clones el agente en los dos.
Checklist de producción
-
maxDurationexplícito en el Route Handler, no el default a ciegas - Hobby vs Pro decidido por frecuencia de cron y techo de 5 vs 13 min
-
CRON_SECRETcreado y validado en el endpoint - Secretos separados por entorno, sin
NEXT_PUBLIC_ - Runtime Logs abiertos el primer día de tráfico
- Rollback: redeploy del deployment previo en el dashboard
Siguiente paso: si el agente ejecuta código, combina Functions con sandboxing. Si todavía no tienes runtime local, el curso gratuito deja un agente para portarlo al Route Handler.
Lecturas relacionadas
Sigue explorando Deploy y otras piezas para builders.



