Introducción
De acuerdo con Wikipedia:
Cloudflare, Inc. es una empresa estadounidense que proporciona una red de entrega de contenido, servicios de seguridad de Internet y servicios de servidores de nombres de dominio distribuidos, localizados entre el visitante y el proveedor de alojamiento del usuario de Cloudflare, y que actúan como proxy inverso para sitios web.
Workers se basa en un motor de ejecución ligero basado en Node.js (no es Node.js directamente). Es mucho más rápido y práctico que utilizar una FaaS en Aliyun FC o Amazon Lambda para desplegar aplicaciones como este blog hecho en Astro, aunque cada tecnología tiene sus ventajas y desventajas. Una ventaja de Workers es la rapidez de su ejecución. Otra, su costo.
Esta guía muestra cómo desplegar una aplicación de Svelte+SvelteKit en Cloudflare Workers (free).
1) Qué hacer en Cloudflare (dashboard)
- Crear/usar una cuenta de Cloudflare (plan Free).
- Ir a
Desarrollo -> Workers y Pagesy habilitar Workers en la cuenta. - (Recomendado) Crear un API Token para deploy desde CLI:
- Ir a
Administrar cuenta -> Tokens de API de cuenta. - En
Account Resources:selecciona tu cuenta. Crear token- Usa la plantilla Edit Cloudflare Workers (tiene los permisos mínimos necesarios)
- Si usarás dominio propio:
Zone -> DNS -> EditarZone -> Rutas de Workers -> Editar(o usar Custom Domain desde UI)
- Seleccionar los
Recursos de zonasegún las zonas que cubrirá el token. - Haz clic en Continue to summary → Create Token.
-
Si usarás dominio propio:
- Tener la zona (
tudominio.com) en Cloudflare. - En el Worker desplegado:
Settings -> Domains & Routes -> Add Custom Domain
- Tener la zona (
-
El nuevo token se puede probar:
curl "https://api.cloudflare.com/client/v4/accounts/xxx123/tokens/verify" \-H "Authorization: Bearer cfat_ABCD_my_token"2) Qué configurar en el proyecto
El proyecto debe estar alineado a Worker puro:
- `main = "build/_worker.js"` - `[assets] directory = "build", binding = "ASSETS"`Si no tienes el account_id, agrégalo:
account_id = "tu_account_id"El account_id lo encuentras en el dashboard de Cloudflare, en la barra lateral derecha de tu dominio, o con:
bunx wrangler whoamiEs, por supuesto, muy importante usar el adapter-cloudflare:
import adapter from '@sveltejs/adapter-cloudflare';Requisitos locales
- Dependencias:
- Node/npm, o Bun (recomendado)
- Wrangler CLI
(vía
npx wranglerobunx wranglertambién sirve)
- Configurar el token en tu entorno local
export CLOUDFLARE_API_TOKEN=cfat_ABCD_my_tokenO de forma permanente en ~/.bashrc, ~/.zshrc o el archivo adecuado para tu shell:
echo 'export CLOUDFLARE_API_TOKEN=tu_token_aqui' >> ~/.bashrcAlternativamente con wrangler:
bunx wrangler loginEsto abre un navegador para OAuth. Personalmente no me gusta.
Si prefieres token directo:
bunx wrangler config3) Variables y secretos (importante)
En tu app actual
Si se usa import.meta.env.VITE_* (build-time), eso significa que:
- Las variables deben existir antes de
npm run buildobun run build(.env, CI vars, etc). - No se leen dinámicamente desde
envde Worker en runtime.
Ejemplos críticos podrían ser:
VITE_APIVITE_API_KEY- Otros
VITE_*de tracking/auth/etc.
Secretos runtime (opcional)
Si luego quieres agregar secretos en runtime:
bunx wrangler secret put NOMBRE_VARIABLEy leerlos desde env.NOMBRE_VARIABLE.
4) Build + deploy (paso a paso)
En los siguientes pasos puedes reemplazar npm por bun en los comandos:
- Instalar dependencias:
npm ci- Configurar token:
export CLOUDFLARE_API_TOKEN=tu_token-
Preparar
.envde build (con tusVITE_*correctas). -
Build:
make build# npm run build# bun run build- Verificar salida:
build/_worker.jsbuild/_app/...
- Probar localmente el Worker:
make preview# bunx wrangler dev- Deploy:
make deploy# bunx wrangler deploy- Probar el Worker, que quedará en:
https://example-frontend.tu-subdominio.workers.dev
o en tu dominio personalizado si lo configuras en el dashboard.
5) Configuración OIDC (Zitadel o algún otro proveedor) para producción
En caso de utilizar algún proveedor de OIDC como Zitadel, debes registrar en el proveedor los endpoints requeridos:
- Redirect URI(s) (callback login).
- Post-logout redirect URI(s).
- Web origins del frontend.
6) Verificaciones post-deploy
Para ver logs:
npx wrangler tail7) Límites de Workers Free que debes considerar (revisados el 7 de abril de 2026)
- 100,000 requests/día.
- CPU 10ms por request.
- 50 subrequests externas por request.
- 128 MB de memoria.
- Tamaño del Worker: 3 MB.
- Static assets por versión: hasta 20,000 archivos.
Si excedes estos límites, tendrás errores tipo 1027/cuotas.
8) Errores típicos
Cannot read properties of undefined (reading 'fetch')
- Causa común: falta binding
ASSETSo deploy ejecutado en modo incorrecto (Pages vs Worker). - En tu estado actual ya está corregido para Worker.
- Variables
VITE_*vacías en producción
- Se construyó sin
.envcorrecto.
- Login Zitadel falla en prod
- Redirect URI / origins no registrados para dominio final.
9) Deploy en dominio propio
Hay 2 formas de hacerlo, asumiendo que el dominio se encuentra en Cloudflare:
A. Usando wrangler.toml
Configurar las rutas:
routes = [ { pattern = "www.example.com/*", zone_name = "example.com" }]Y luego hacer el deploy normal:
bunx wrangler deployB. En el dashboard de Cloudflare
- Ve a Workers & Pages → tu worker → Settings → Triggers
- Clic en Add Custom Domain
- Escribe
www.example.com - Cloudflare crea automáticamente el registro DNS y el certificado TLS
Dominio fuera de Cloudflare
Si el dominio no está en Cloudflare:
Primero debes agregar el dominio a Cloudflare (o al menos usar un registro DNS externo):
En el DNS de tu registrador, crea un registro CNAME:
En tinydns, por ejemplo:
Cwww:tu-proyecto.tu-subdominio.workers.dev:86400Luego en Cloudflare, ve al worker y en Triggers clic en Add Custom Domain y agrega www.example.com.
Diferencia entre routes y custom_domain
| Característica | routes | custom_domain |
|---|---|---|
| Requiere zona en CF | Sí | Sí |
| Configurable en toml | Sí | Sí |
| TLS automático | Manual (ya existente) | Automático |
| Comparte con otros workers | Sí (por patrón) | No |
Para un subdominio dedicado al worker, custom_domain es la opción más limpia:
routes = [ { pattern = "ssr.example.com/*", custom_domain = true, zone_name = "example.com" }]O la sintaxis alternativa:
[[env.production.routes]]pattern = "ssr.example.com/*"zone_name = "example.com"Bonus: Reglas de Makefile útiles
deploy: bunx wrangler deploy
preview: bunx wrangler dev
build: @echo "Building with $(DOTENV_FILE)" DOTENV_FILE=$(DOTENV_FILE) bun run buildFuentes oficiales usadas
- Workers limits: https://developers.cloudflare.com/workers/platform/limits/
- Workers pricing: https://developers.cloudflare.com/workers/platform/pricing/
- Wrangler config (
assets): https://developers.cloudflare.com/workers/wrangler/configuration/ - Static assets binding: https://developers.cloudflare.com/workers/static-assets/binding/
- Environment vars/secrets:
- Routing/domains:
