Guía9 min

Preview vs Production para agentes IA: Vercel, Railway y Workers

Resumen

Cómo aislar el agente de un PR para que no dispare el bot de Telegram de producción, no gaste la API key real ni pise la base: Preview de Vercel, environments de Railway (persistentes vs PR), env de Wrangler y secretos por entorno.

VercelRailwayCloudflare
Dos entornos paralelos de un agente, preview a la izquierda y producción a la derecha

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.

Un PR no debería hablarle a tus usuarios. Si el preview usa el token de Telegram de Production, cada push a una rama abre un segundo bot (o el mismo) contestando basura. Preview vs Production no es un detalle de hosting: es el aislamiento de secretos, webhooks y datos. Las fuentes oficiales fueron consultadas el 3 de septiembre de 2026.

El CI/CD cubre tests y el gate humano. Secretos cubre cómo inyectar llaves. Esta guía cubre qué llave va a qué entorno.

La regla

Preview (rama / PR) = bot de prueba, API key con tope bajo, base descartable. Production (main) = bot real, llave con presupuesto, base que duele perder.

Si una variable no está marcada distinta por entorno, asume que el preview gasta Production.

Vercel: dos URLs de preview

Vercel crea un Preview al pushear a una rama que no es la de producción (suele ser main), al abrir un PR en GitHub/GitLab/Bitbucket/Origin, o al correr vercel sin --prod. Docs de Preview Deployments (hoy): cada deploy genera una URL única. Production se dispara al pushear a la rama de prod o con vercel --prod; si el deploy de prod sale bien, Vercel apunta los dominios de producción al nuevo. El primer deploy de un proyecto nuevo siempre es production; las reglas de preview aplican después.

Hay dos URLs prácticas:

  • Branch-specific: siempre el último deploy de esa rama.
  • Commit-specific: el deploy exacto de ese commit (la URL única).

Las Environment Variables (docs, hoy) se asignan por entorno: Production (próximo deploy de prod / push a la rama / vercel --prod), Preview (próximo Preview), Development (vercel dev / vercel env pull). Van cifradas en reposo y las ve quien tiene acceso al proyecto. Sensitive existe como tipo aparte: no la trates como un flag de “All”. Una API key solo en Production no llega al preview — y al revés: si la pones en los tres, el PR gasta tu saldo.

Para un agente: webhook de Telegram/Slack en Preview = otro bot o un secret de test. El mismo token en los tres entornos es el incidente clásico.

Railway: persistente vs PR

Todo proyecto nace con production. Los cambios de un servicio viven dentro de un environment y no tocan los demás. Docs de Environments (hoy), dos tipos:

  • Persistente: pensados para quedarse, aislados de production en config. Patrón oficial: un staging que auto-despliega desde la rama staging, con variables de staging. Sirve para un agente que quieres “casi prod” todo el mes.
  • PR environments: temporales. Se crean al abrir el Pull Request y se borran en cuanto el PR se mergea o se cierra. Perfectos para no dejar Machines de prueba vivas.

No uses el environment de production para probar un tool nuevo. Railway lo aísla; tú no lo anules copiando las variables a mano.

Workers: un Worker por environment

Wrangler (docs, hoy) crea un Worker distinto: nombre <top-level-name>-<environment-name>. Ejemplo oficial: proyecto my-worker + env dev despliega como my-worker-dev. En el toml:

name = "mi-agente"
[env.dev]

Los environments se usan con --env / -e: npx wrangler dev -e=dev y npx wrangler deploy -e=dev. Los secretos se ponen por environment (wrangler secret put --env dev). El cron de Production no debe existir en dev si dispara el mismo digest a clientes. Custom domain / route solo en el Worker de prod (el ejemplo oficial separa route = "example.com" vs [env.dev] route = "dev.example.com").

Qué se duplica y qué no

Aislamiento de secretos y webhooks entre preview y producción

RecursoPreview / stagingProduction
Token del botBot de pruebaBot real
API key del modeloProyecto aparte, tope de gasto bajoProyecto con presupuesto y alerta
Base / volumenVacía o seedLa de verdad, con backup
CronOff o horario de oficinaEl real, en UTC
Webhook URLURL del preview / my-worker-devDominio estable
Dominio customNo

GitHub Actions Environments protege el job de Production con revisores. Úsalo para el deploy a main; el preview no necesita aprobación humana.

Errores comunes

Errores típicos al mezclar preview y producción de un agente

SíntomaCausa típicaFix
El bot de prod contesta desde un PRToken copiado a PreviewToken distinto; rota el de prod si ya se filtró
Factura OpenAI en un PRAPI key en “All environments”Key de preview con tope; prod solo en Production
Railway PR environment vivo 2 semanasPR abierto y olvidadoCiérralo; el env se borra al cerrar
Worker dev dispara el cron de clientesMismos [triggers].crons sin --envCron solo en el env de prod
Preview apunta a la BD de prodConnection string no separadaVariable distinta por entorno

Relación con el resto

  • Cómo inyectar las llaves: secretos.
  • Cómo no publicar un PR roto: CI/CD.
  • Cómo volver atrás si prod se rompió: rollback.

Aislar entornos no reemplaza tests. Evita que el test se ejecute contra tus usuarios.

El ensayo mínimo: abre un PR que solo cambia un string del prompt, confirma que el bot de Production no habla y que el de Preview sí (o que Preview no tiene webhook). Si no puedes demostrar eso, los entornos no están aislados aunque el dashboard muestre tres columnas de variables.

Checklist

  • API key de Preview ≠ Production, con tope de gasto
  • Token de bot de Preview es otro bot
  • Cron apagado en Preview / env dev
  • Railway: PR environments se cierran con el PR
  • Workers: wrangler secret put --env por environment
  • Ensayo: abre un PR y confirma que el bot de prod no habla

Si el preview no tiene bot propio, apaga el webhook en Preview. Un agente mudo en el PR es más seguro que un agente que habla con la llave de Production. El aislamiento barato es “no conectar”; el aislamiento correcto es “conectar a otro bot”. El mismo criterio aplica a crons: un digest diario en Preview que pega a clientes reales es un incidente, no una prueba.

Railway no “esconde” production si pegas el mismo DATABASE_URL en el PR environment: el tipo persistente vs PR solo aísla si las variables son distintas. Vercel cifra en reposo; eso no impide que un Preview con la key de prod gaste tokens. Workers: my-worker-dev es otro proceso, no un flag. Si le pones la misma ruta y el mismo cron, es un segundo bot en producción con otro nombre.

Siguiente paso: si el preview ya está aislado y prod se rompe igual, el problema es el deploy — rollback y logs. Si todavía no tienes runtime, el curso gratuito deja un agente local para cablear dos .env antes de subir.