Desplegar un agente IA en Cloudflare Workers: guía práctica
Resumen
Tutorial paso a paso para correr un agente de IA en Cloudflare Workers: Wrangler, handler fetch para webhooks, Cron Triggers para jobs periódicos, secretos cifrados, tabla de límites Free vs Paid y cuándo Workers gana frente a Vercel, 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 Cloudflare Workers: un proceso en el borde, cobrado por CPU (no por reloj), con HTTPS incluido y un cron nativo. Para un agente de webhooks o un job periódico que llama a un LLM, ese modelo es el que más se parece a “gratis hasta que escala”. Las fuentes oficiales fueron consultadas el 3 de septiembre de 2026.
Si tu agente necesita un proceso vivo con sqlite y Docker, Railway o el self-hosting en VPS encajan mejor. Aquí el foco es el Worker.
Cuándo sí y cuándo no
Sí, si el agente:
- Responde webhooks (Telegram, Slack, GitHub) y sale en milisegundos más la espera al LLM.
- Corre un cron: digest diario, reindex de RAG, alerta de costos.
- Tiene poco estado: el estado vive en KV, D1 o un API externo, no en RAM del proceso.
No, si el agente:
- Ejecuta código de usuario o un sandbox largo: 128 MB de RAM y 3–10 MB de Worker no dan para un runtime de coding.
- Mantiene un socket o un long-poll abierto horas: el runtime se actualiza varias veces por semana y corta inflight a 30 s de gracia.
- Necesita GPU o binarios nativos.
La regla: Workers es un handler, no un servidor. Si tu arquitectura asume while (true), no es Workers.
Límites que sí importan (Free vs Paid)
| Límite | Free | Paid (USD 5/mes) |
|---|---|---|
| Requests | 100,000/día (reset 00:00 UTC; Error 1027 al pasarte) | sin límite diario de requests |
| CPU por request HTTP | 10 ms | default 30 s, máximo 5 min |
| Wall clock HTTP | sin límite duro mientras el cliente esté conectado | igual |
| Cron wall clock | 15 min | 15 min |
| Memoria | 128 MB | 128 MB |
| Subrequests | 50/request | 10,000/request |
| Tamaño del Worker | 3 MB | 10 MB |
| Variables de entorno | 64 × 5 KB | 128 × 5 KB |
| Cron Triggers por cuenta | 5 | 250 |
Dos lecturas prácticas:
- El cobro es por CPU, no por espera. Llamar a OpenAI y esperar 8 s no consume el cupo de 10 ms / 30 s. El loop que parsea JSON sí.
waitUntil()solo alarga 30 s después de responder o de que el cliente se desconecte. Trabajo post-respuesta largo → Queues o Workflows, no unforen el handler.
Paso 1 — Proyecto con Wrangler
Wrangler pide Node ≥ 16.17. Con pnpm:
pnpm create cloudflare@latest mi-agente
cd mi-agente
pnpm wrangler login
El scaffold deja un Worker con fetch. Eso cubre el webhook. El cron va en el mismo archivo.
Paso 2 — fetch + scheduled en un Worker

export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext) {
if (request.method !== "POST") {
return new Response("ok", { status: 200 });
}
const event = await request.json();
ctx.waitUntil(runAgent(event, env));
return new Response("accepted", { status: 202 });
},
async scheduled(controller: ScheduledController, env: Env, ctx: ExecutionContext) {
ctx.waitUntil(runDigest(env, controller.cron));
},
};
El 202 vuelve al webhook en milisegundos; el LLM corre en waitUntil. Si el digest dura más de 30 s tras responder, no uses waitUntil para eso: el scheduled ya tiene 15 min de wall clock.
Cron en Wrangler (UTC):
[triggers]
crons = ["0 14 * * *"]
Prueba local del cron, según la docs de scheduled:
curl "http://localhost:8787/cdn-cgi/handler/scheduled?format=json"
Paso 3 — Secretos, no variables
La API key del modelo es un secreto, no una env var del wrangler.toml. Cloudflare cifra el binding y lo inyecta en env:
pnpm wrangler secret put OPENAI_API_KEY
En el handler: env.OPENAI_API_KEY. El resto (rotación, no loguear, no NEXT_PUBLIC_) está en secretos y variables de entorno.
Paso 4 — Deploy y verificar
pnpm wrangler deploy
curl -s https://mi-agente.<subdominio>.workers.dev
Criterio de éxito: el GET responde ok, un POST de prueba entra a logs (pnpm wrangler tail) y el cron aparece en Workers → Triggers. Custom domain: Workers → Settings → Domains; el certificado lo emite Cloudflare.
Relación con el resto del stack de deploy
Workers cubre el borde. No cubre un proceso con sqlite, un sandbox de código ni un reverse proxy que tú parcheas. Esa frontera es la que evita canibalizar las otras guías:
- Comparativa de plataformas (decidir): Vercel vs Workers vs VPS.
- Proceso vivo con volumen: Railway.
- Control total del servidor: Docker en VPS.
- Pipeline de tests antes de publicar: CI/CD con GitHub Actions.
Si el webhook en Workers es la puerta y el trabajo pesado vive en otro servicio, el Worker solo valida, encola y responde 2xx. Esa es la forma correcta de combinarlos, no clonar el agente en los dos sitios.
Errores comunes

| Síntoma | Causa típica | Fix |
|---|---|---|
| Error 1027 | Te pasaste de 100k requests/día en Free | Sube a Paid o recorta healthchecks cada 10 s |
| CPU exceeded (10 ms) | Parseo pesado o loop en el handler, no la espera al LLM | Mueve CPU al scheduled o a una Queue; perfila con DevTools |
| Cron no dispara | Falta [triggers].crons o el handler scheduled | Añade ambos; prueba con /cdn-cgi/handler/scheduled |
Secret undefined | Lo pusiste en [vars] del toml (queda en el repo) | wrangler secret put; borra el valor del toml |
| Work post-202 se corta | waitUntil tope 30 s | Cron de 15 min, Queue o Workflow |
Checklist de producción
- Free vs Paid decidido con la tabla de requests/CPU, no a ojo
- API keys por
wrangler secret put, no en el toml - Webhook responde 2xx rápido; el LLM va en
waitUntilo en cron - Cron en UTC, testeado en local
-
wrangler tailabierto el primer día de tráfico real - Deployment previo identificable en el dashboard para volver atrás a mano
Siguiente paso: si el Worker es solo la puerta y el agente pesado vive en otro lado, combina esta guía con Railway o el VPS con Docker. Si todavía no tienes runtime local, el curso gratuito deja un agente corriendo para portarlo al fetch.
Lecturas relacionadas
Sigue explorando Deploy y otras piezas para builders.



