Capítulo 10: Cloudflare Pages — Publicando aplicaciones modernas sin servidores¶
Objetivos del capítulo¶
Al terminar este capítulo serás capaz de:
- Explicar qué es Cloudflare Pages, cómo funciona su arquitectura y por qué representa un cambio de paradigma frente al hosting tradicional.
- Conectar un repositorio de GitHub o GitLab a Cloudflare Pages y configurar un proyecto desde cero, eligiendo el framework y las opciones de build correctas.
- Comprender el sistema de build v3, incluyendo versiones de runtimes, variables de entorno automáticas y presets para más de doce frameworks populares.
- Configurar dominios personalizados para tus proyectos —como
elprofe.orgomasterfinanzas.com— y aprovechar el HTTPS automático que ofrece la plataforma. - Usar los archivos
_redirectsy_headerspara controlar redirecciones, reescrituras y cabeceras HTTP sin necesidad de un servidor de aplicaciones. - Crear funciones serverless con Pages Functions que se ejecutan en el edge, integrando lógica de backend directamente en tu proyecto estático.
- Aprovechar los preview deployments para revisar cambios antes de publicar en producción y colaborar eficientemente con equipos.
- Comparar Cloudflare Pages con plataformas alternativas como Vercel, Netlify y Firebase Hosting, eligiendo la opción más adecuada para cada proyecto.
- Identificar los límites del plan gratuito y del plan de pago, y entender cuándo tiene sentido escalar o migrar a Workers.
- Aplicar las buenas prácticas del capítulo para mantener proyectos limpios, seguros y de alto rendimiento en producción.
Introducción¶
Imagina que has pasado semanas construyendo una plataforma educativa. Tienes el código en GitHub, las pantallas diseñadas y un dominio esperando en Cloudflare. Pero de repente aparece el momento que nadie menciona en los tutoriales: ¿cómo lo pones en internet? ¿Qué servidor configuras? ¿Nginx o Apache? ¿En qué región del mundo? ¿Quién instala los certificados SSL? ¿Quién escala cuando tus estudiantes se conectan todos al mismo tiempo?
Durante años, esas preguntas fueron el primer gran obstáculo entre una idea y su publicación real. Había que contratar un VPS, configurar un servidor, instalar dependencias, aprender a usar pm2 o systemd, rogar que los certificados no expiraran, y rezar para que el servidor aguantara el tráfico de una publicación viral. No era desarrollo web; era operaciones de sistemas disfrazadas de desarrollo web.
Cloudflare Pages llegó en 2021 para cambiar esa conversación de raíz. No es solo una plataforma de hosting. Es una infraestructura completa que convierte tu repositorio de código en un sitio web global, servido desde más de 330 ciudades en el mundo, con HTTPS automático, dominios personalizados, previsualizaciones por cada rama de Git y —desde 2022— capacidad para ejecutar lógica de backend directamente en el edge. Todo esto, gratis para la mayoría de los proyectos.
En el capítulo anterior (Capítulo 9) aprendiste a configurar Cloudflare desde cero: activar un dominio, ajustar DNS, entender los planes. En el Capítulo 8 estudiamos la CDN de Cloudflare, esa red que cubre el 74.7 % del mercado de distribución de contenidos. Cloudflare Pages es, en esencia, la manera más directa de publicar tu código sobre esa misma infraestructura sin tocar un solo servidor.
Nuestro ejemplo principal a lo largo de este capítulo será elprofe.org, una plataforma educativa ficticia pero técnicamente completa, con sus subdominios (api.elprofe.org, ia.elprofe.org, mail.elprofe.org), sus necesidades de redirecciones, sus reglas de seguridad en cabeceras HTTP y sus pequeñas funciones de backend para autenticación y estadísticas. También veremos cómo nlink.uk, el acortador de URLs, y masterfinanzas.com, la marca financiera, se benefician de las mismas herramientas.
Lo que vas a descubrir en este capítulo es que publicar una aplicación moderna ya no es una tarea de devops. Es una tarea de desarrollador. Y Cloudflare Pages es una de las razones más poderosas por las que ese cambio ocurrió.
Durante décadas, el modelo de publicación web siguió un ritual conocido por todo desarrollador experimentado: escribe el código, comprímelo en un archivo .zip o conéctate por FTP, súbelo a un servidor, reza para que las rutas coincidan y para que no hayas olvidado ningún archivo. Si algo salía mal en producción, el proceso de diagnóstico comenzaba con un SSH al servidor y terminaba, horas después, con un parche aplicado directamente sobre el código en producción —lo que en la industria se conoce, no sin cierto humor oscuro, como "cirugía de corazón abierto en el paciente despierto".
El modelo JAMstack (JavaScript, APIs, Markup) que popularizaron Netlify y Vercel a partir de 2015 cambió esa dinámica: si puedes construir tu sitio de antemano y convertirlo en archivos estáticos, no necesitas un servidor de aplicaciones. Necesitas una CDN. Y si la CDN puede ejecutar un poco de lógica también —para manejar formularios, autenticar usuarios, hacer llamadas a APIs externas— entonces el servidor de aplicaciones se vuelve completamente prescindible para la mayoría de los proyectos.
Cloudflare Pages lleva este modelo al siguiente nivel porque Cloudflare no es una startup que alquila servidores de Amazon. Es la empresa que opera una de las redes de distribución de contenidos más grandes del planeta, con más de 330 puntos de presencia en más de 100 países. Cuando haces deploy en Pages, tus archivos no van a un data center en Virginia o en Irlanda: van a todos los puntos de presencia de Cloudflare simultáneamente. Tu sitio está en São Paulo, en Lagos, en Tokio y en la Ciudad de México al mismo tiempo, con una sola acción.
Este capítulo es técnico y práctico en partes iguales. Para cuando lo termines, elprofe.org estará en el aire —con HTTPS, dominio propio, headers de seguridad, redirecciones configuradas y una Function de backend que registra estadísticas desde el edge.
10.1 — ¿Qué es Cloudflare Pages y por qué cambió todo?¶
La promesa original del web estático¶
En los primeros días de la web, todo era estático. Un servidor devolvía un archivo HTML, el navegador lo mostraba. Sin base de datos, sin lógica de servidor, sin sesiones. Era simple, rápido y barato. El problema era que también era limitado: no podías mostrar contenido personalizado, no podías procesar formularios, no podías autenticar usuarios.
La respuesta fue el modelo dinámico: PHP, Rails, Django. El servidor recibía cada solicitud, consultaba la base de datos, construía el HTML al momento y lo enviaba. Flexible y poderoso, sí, pero costoso en términos de infraestructura, mantenimiento y rendimiento.
La siguiente evolución fue el modelo JAMstack (JavaScript, APIs, Markup), popularizado hacia 2015-2016. La idea central es separar el frontend del backend: el sitio se construye de antemano (en el proceso de build), se convierte en archivos estáticos y se sirve desde una CDN. Cualquier lógica dinámica se delega a APIs externas o a funciones serverless. El resultado: sitios increíblemente rápidos, seguros (no hay servidor de aplicaciones que atacar), económicos (CDN es barato) y escalables (la CDN ya está distribuida globalmente).
Cloudflare Pages es, en su núcleo, la implementación más sofisticada de este modelo. Pero con una diferencia fundamental respecto a sus competidores: no es una startup de hosting que usa AWS o GCP por debajo. Es Cloudflare. La misma empresa que tiene más de 330 puntos de presencia (PoPs) propios, que maneja una fracción significativa del tráfico global de internet, que tiene su propio runtime de JavaScript en el edge. Cuando haces deploy en Cloudflare Pages, tus archivos no van a un servidor en us-east-1 de Amazon. Van a todos los PoPs de Cloudflare simultáneamente.
La arquitectura que lo hace posible¶
┌─────────────────────────────────────────────────────────────────────┐
│ CLOUDFLARE PAGES — VISIÓN GLOBAL │
├──────────────────────────┬──────────────────────────────────────────┤
│ Tu repositorio (GitHub) │ Cloudflare Build System │
│ ┌────────────────────┐ │ ┌──────────────────────────────────┐ │
│ │ main branch │──┼─▶│ npm run build → dist/ │ │
│ │ feature/login │ │ │ Validación + optimización │ │
│ │ fix/typo │ │ └──────────────┬───────────────────┘ │
│ └────────────────────┘ │ │ │
│ │ ▼ │
│ │ ┌──────────────────────────────────┐ │
│ │ │ 330+ PoPs en el mundo │ │
│ │ │ Frankfurt ● Tokio ● São Paulo │ │
│ │ │ Miami ● Lagos ● Estambul │ │
│ │ │ CDMX ● Bogotá ● Madrid ● Seúl │ │
│ │ └──────────────┬───────────────────┘ │
│ │ │ │
│ │ ▼ │
│ │ ┌──────────────────────────────────┐ │
│ │ │ Usuario en cualquier parte del │ │
│ │ │ mundo — latencia mínima │ │
│ │ └──────────────────────────────────┘ │
└──────────────────────────┴──────────────────────────────────────────┘
Cuando un usuario accede a elprofe.org, Cloudflare resuelve la solicitud desde el PoP más cercano. Los archivos estáticos (HTML, CSS, JS, imágenes) ya están ahí, almacenados en caché. No hay un salto a un servidor de origen; no hay tiempo de espera por generación dinámica. La respuesta puede llegar en decenas de milisegundos desde cualquier lugar del planeta.
¿Cuándo llegó y cómo evolucionó?¶
Cloudflare Pages se anunció en beta en diciembre de 2020 y salió a disponibilidad general en abril de 2021. En ese momento, era básicamente un competidor directo de Netlify y Vercel: conectas un repositorio, configuras el comando de build y listo. Bueno, pero sin nada extraordinario más allá de la red de Cloudflare.
El cambio real llegó en 2022, cuando Cloudflare introdujo Pages Functions: la capacidad de agregar funciones serverless directamente en el directorio /functions/ de tu proyecto. De repente, Pages dejó de ser solo un hosting estático para convertirse en una plataforma de aplicaciones completas. Podías tener un blog estático con una API de comentarios, o una tienda con lógica de carrito, sin ningún servidor adicional.
Desde entonces, la evolución ha sido constante. En 2024 y 2025, Cloudflare comenzó a converger Pages hacia Workers —su plataforma de computación en el edge—, haciendo que los dos productos compartan cada vez más infraestructura. Para 2026, muchos proyectos que antes se construían como Workers independientes ahora se construyen directamente como proyectos de Pages con Functions, aprovechando el sistema de despliegue integrado con Git.
Por qué el modelo tradicional ya no tiene sentido para la mayoría¶
Piensa en primariajuanescutia.edu.mx, la escuela primaria del ejemplo. Su sitio web muestra horarios, fotos de eventos escolares, información de contacto y el calendario del ciclo. ¿Necesita un servidor VPS con Nginx corriendo 24/7 para eso? No. ¿Necesita pagar $20-40 al mes por hosting? No. ¿Necesita que alguien renueve el certificado SSL cada año? Absolutamente no.
Con Cloudflare Pages, ese sitio se construye una vez, se despliega en segundos y se sirve desde el edge global de forma completamente gratuita. El certificado SSL se gestiona automáticamente. Si el director sube una nueva foto de la obra de teatro escolar, solo hace push al repositorio y Pages redespliega en minutos.
Ese es el cambio que Cloudflare Pages produce: no solo simplifica el proceso técnico, sino que democratiza el acceso a una infraestructura de nivel empresarial.
10.2 — Cómo funciona el pipeline de publicación¶
El ciclo de vida de un deploy¶
Entender qué pasa internamente cuando haces push al repositorio es fundamental para depurar problemas, optimizar tiempos de build y tomar decisiones arquitectónicas. El proceso tiene cuatro fases claramente diferenciadas.
┌─────────────────────────────────────────────────────────────────────────┐
│ PIPELINE DE PUBLICACIÓN — CLOUDFLARE PAGES │
│ │
│ 1. TRIGGER 2. BUILD 3. DEPLOY 4. CDN │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐ │
│ │ git push │───────▶│ Clonar │───────▶│ Upload │─────▶│ 330+ │ │
│ │ PR merge │ │ repo │ │ assets │ │ PoPs │ │
│ │ manual │ │ Instalar │ │ Invalidar│ │ cache │ │
│ │ trigger │ │ deps │ │ caché │ │ update │ │
│ └──────────┘ │ Ejecutar │ └──────────┘ └─────────┘ │
│ │ build │ │
│ │ command │ ┌──────────────────────────┐ │
│ └──────────┘ │ URL de deploy: │ │
│ │ *.pages.dev (preview) │ │
│ │ elprofe.org (producción) │ │
│ └──────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
Fase 1 — Trigger (disparador): Cloudflare detecta un evento en el repositorio conectado. Puede ser un push a cualquier rama, la apertura de un pull request, un merge, o un trigger manual desde el panel de Pages. También es posible usar la API de Cloudflare para disparar deploys desde pipelines de CI/CD externos.
Fase 2 — Build: Cloudflare asigna un worker de build (una máquina efímera dentro de su infraestructura) que:
- Clona el repositorio en el commit exacto que disparó el evento.
- Establece las variables de entorno (tanto las automáticas como las que configuraste).
- Instala las dependencias usando la caché cuando es posible.
- Ejecuta el comando de build que configuraste (ej: npm run build).
- Valida que el directorio de salida exista y no supere los límites de tamaño.
Fase 3 — Deploy: Los archivos del directorio de salida se cargan al sistema de almacenamiento global de Cloudflare. Pages calcula los hash de cada archivo y solo sube los que cambiaron respecto al deploy anterior (deploy diferencial). Una vez cargados, se registra la nueva versión del despliegue.
Fase 4 — CDN: Cloudflare propaga los nuevos archivos a todos sus PoPs. La invalidación de caché es automática. Normalmente, el proceso completo desde el push hasta que el sitio está actualizado globalmente toma entre 30 segundos y 5 minutos, dependiendo del tamaño del build.
Deployments, ramas y URLs¶
Una característica poderosa de Pages es que cada rama de Git puede tener su propia URL de preview. Si trabajas en una rama llamada feature/nueva-portada, Cloudflare Pages publicará automáticamente esa versión en una URL como:
La rama configurada como "producción" (normalmente main o master) se sirve desde:
- La URL de Pages por defecto: elprofe-org.pages.dev
- Tu dominio personalizado: elprofe.org
Cada deploy queda registrado con un ID único, su commit, la rama, el tiempo de build y un enlace permanente. Puedes hacer rollback a cualquier deploy anterior con un solo clic, sin necesidad de revertir el código.
El build es efímero¶
Una diferencia conceptual importante: el entorno de build de Pages es completamente efímero. No persiste entre builds. Esto significa que cualquier archivo que tu proceso de build necesite debe estar en el repositorio, ser descargado durante el build, o estar disponible como variable de entorno. No puedes confiar en que un archivo que "quedó" de un build anterior esté disponible. Esta restricción es en realidad una garantía de reproducibilidad: cualquier build debería poder ejecutarse desde cero y producir el mismo resultado.
10.3 — Conectando tu repositorio y configurando el proyecto¶
Paso a paso: el primer deploy de elprofe.org¶
Supongamos que elprofe.org es un sitio construido con Astro, el framework moderno para contenido web. El repositorio está en GitHub. Veamos cómo conectarlo a Cloudflare Pages.
1. Entrar al panel de Cloudflare
Desde dash.cloudflare.com, en la barra lateral izquierda, selecciona "Workers & Pages". Luego haz clic en "Create application" y elige la pestaña "Pages".
2. Conectar el repositorio
Cloudflare te pedirá que autorices acceso a tu cuenta de GitHub o GitLab. Puedes dar acceso a todos los repositorios o solo a los seleccionados. Para elprofe.org, seleccionamos el repositorio correspondiente.
3. Configurar el build
Esta es la pantalla más importante del proceso de setup:
┌─────────────────────────────────────────────────────────────┐
│ CONFIGURACIÓN DE BUILD — CLOUDFLARE PAGES │
├─────────────────────────────────────────────────────────────┤
│ Nombre del proyecto: elprofe-org │
│ Rama de producción: main │
│ Framework preset: Astro │
│ ┌────────────────────────────┐ │
│ Build command: │ npm run build │ │
│ Build output dir: │ dist │ │
│ └────────────────────────────┘ │
│ │
│ Variables de entorno: │
│ ┌────────────────────┬─────────────────────────────────┐ │
│ │ NODE_VERSION │ 22 │ │
│ │ PUBLIC_SITE_URL │ https://elprofe.org │ │
│ │ PUBLIC_API_BASE │ https://api.elprofe.org │ │
│ └────────────────────┴─────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Cloudflare detecta automáticamente muchos frameworks si encuentra los archivos de configuración correspondientes (astro.config.mjs, vite.config.ts, etc.) y pre-rellena los campos correctos.
4. El primer deploy
Al hacer clic en "Save and Deploy", Cloudflare inicia el pipeline. Puedes ver los logs en tiempo real:
21:04:32.108 Clonando repositorio...
21:04:33.891 Usando Node.js 22.16.0
21:04:33.910 Instalando dependencias con npm...
21:04:47.230 added 342 packages in 13.3s
21:04:47.231 Ejecutando build command: npm run build
21:04:51.782 dist/ generado con 847 archivos
21:04:51.783 Build completado en 18.6s
21:04:52.100 Subiendo 847 archivos...
21:04:58.441 Deploy exitoso
21:04:58.442 URL: https://elprofe-org.pages.dev
En menos de un minuto, elprofe.org está en internet, servido desde la red global de Cloudflare.
Trabajando con la API de Cloudflare para automatización¶
Para proyectos más avanzados, la API de Cloudflare permite disparar deploys desde pipelines externos. Este patrón, llamado Direct Upload, desacopla el build de Cloudflare y te da control total sobre el entorno de construcción:
# Disparar un deploy directo via API (Direct Upload)
npx wrangler pages deploy ./dist --project-name=elprofe-org --branch=main
10.4 — El sistema de build: frameworks, versiones y variables de entorno¶
Build System v3: el entorno estándar de 2025-2026¶
En mayo de 2025, Cloudflare lanzó el Build System v3, que actualiza todos los runtimes a versiones modernas. Este es el entorno que todo nuevo proyecto usa por defecto:
| Runtime | Versión disponible |
|---|---|
| Node.js | 22.16.0 |
| Python | 3.13.3 |
| Go | 1.24.3 |
| Bun | 1.2.15 |
Nota: Si tu proyecto fue creado antes de mayo de 2025, puede estar usando el Build System v2. Puedes migrarlo manualmente desde la configuración del proyecto en el panel de Cloudflare.
Variables de entorno automáticas¶
Cloudflare inyecta automáticamente cinco variables de entorno en cada proceso de build:
| Variable | Valor / Descripción |
|---|---|
CI |
true — indica entorno de integración continua |
CF_PAGES |
1 — confirma que estás en Cloudflare Pages específicamente |
CF_PAGES_BRANCH |
Nombre de la rama que disparó el build (ej: main) |
CF_PAGES_COMMIT_SHA |
Hash completo del commit (40 caracteres) |
CF_PAGES_URL |
URL de preview del deploy actual |
Un uso práctico de CF_PAGES_BRANCH en el código de build:
// astro.config.mjs
import { defineConfig } from 'astro/config';
const isProd = process.env.CF_PAGES_BRANCH === 'main';
export default defineConfig({
site: isProd ? 'https://elprofe.org' : process.env.CF_PAGES_URL,
});
Presets de frameworks¶
┌──────────────────────┬───────────────────────────────┬─────────────────────────┐
│ Framework │ Build Command │ Directorio de salida │
├──────────────────────┼───────────────────────────────┼─────────────────────────┤
│ HTML puro │ (ninguno) │ / │
│ React (CRA) │ npm run build │ build │
│ React (Vite) │ npm run build │ dist │
│ Vue 3 (Vite) │ npm run build │ dist │
│ Astro │ npm run build │ dist │
│ Nuxt 3 │ npm run build │ .output/public │
│ Next.js │ npx @cloudflare/next-on-pages │ .vercel/output/static │
│ SvelteKit │ npm run build │ .svelte-kit/cloudflare │
│ Hugo │ hugo │ public │
│ Jekyll │ jekyll build │ _site │
│ MkDocs │ mkdocs build │ site │
│ Gatsby │ gatsby build │ public │
│ Eleventy │ npx @11ty/eleventy │ _site │
└──────────────────────┴───────────────────────────────┴─────────────────────────┘
El caso especial de Next.js¶
Next.js tiene renderizado del lado del servidor (SSR), rutas API y otras características que requieren un runtime de Node.js. Para que funcione en Cloudflare Pages existe @cloudflare/next-on-pages, que transforma la salida de Next.js en un formato compatible con el runtime de Cloudflare Workers:
npm install --save-dev @cloudflare/next-on-pages
# Build command para Cloudflare Pages:
npx @cloudflare/next-on-pages@1
Advertencia: No todas las características de Next.js son compatibles con el edge runtime. Revisa la documentación de compatibilidad en la guía oficial antes de migrar.
Variables de entorno sensibles y secretos¶
Para variables sensibles —claves de API, credenciales de base de datos— Cloudflare Pages ofrece variables cifradas. Estas se almacenan cifradas y nunca se exponen en los logs de build. La separación entre entorno "Producción" y "Preview" permite usar bases de datos o claves de test en deployments de preview, y las reales solo en producción.
10.5 — Dominios personalizados y HTTPS automático¶
Conectar elprofe.org a Cloudflare Pages¶
Cuando un proyecto de Pages se crea, recibe una URL gratuita con el formato nombre-proyecto.pages.dev. Para un proyecto serio queremos elprofe.org. El proceso de conectar un dominio personalizado es uno de los más simples en toda la infraestructura web moderna, especialmente cuando el dominio ya está en Cloudflare (como aprendimos en el Capítulo 9):
- En el panel de Pages, ve al proyecto → "Custom domains" → "Set up a custom domain".
- Ingresa el dominio:
elprofe.org - Cloudflare detecta automáticamente que el dominio está en tu cuenta y crea el registro DNS necesario.
- El certificado SSL se provisiona automáticamente en segundos.
- Resultado:
elprofe.org→ HTTPS → Cloudflare Pages → tu sitio.
┌──────────────────────────────────────────────────────────────────┐
│ FLUJO DE DOMINIO PERSONALIZADO │
│ │
│ Usuario escribe: elprofe.org │
│ │ │
│ ▼ │
│ DNS de Cloudflare resuelve: │
│ elprofe.org CNAME elprofe-org.pages.dev │
│ │ │
│ ▼ │
│ Cloudflare Edge (PoP más cercano) │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ • Termina TLS (HTTPS automático) │ │
│ │ • Sirve archivos desde caché (si disponible) │ │
│ │ • Aplica reglas de _redirects y _headers │ │
│ │ • Ejecuta Pages Functions (si aplica) │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ Respuesta al usuario (HTML, CSS, JS, imágenes) │
└──────────────────────────────────────────────────────────────────┘
Dominios externos (fuera de Cloudflare)¶
Si el dominio está registrado en otro proveedor (GoDaddy, Namecheap, etc.), el proceso requiere configurar manualmente el registro DNS:
- Para subdominios (
blog.elprofe.org): Un registro CNAME estándar haciaelprofe-org.pages.dev. - Para el dominio apex (
elprofe.org): Algunos registradores soportan CNAME en el apex. Otros requieren un registroAespecial.
Dato importante: Cloudflare Pages permite hasta 100 dominios personalizados en el plan gratuito y hasta 250 en el plan Workers Paid.
HTTPS automático: el certificado que nunca caduca¶
- Provisioning: El certificado se crea en segundos al agregar el dominio personalizado.
- Renovación: Cloudflare lo renueva automáticamente. Nunca hay alertas de certificado por expirar.
- Cobertura: Tanto el dominio apex (
elprofe.org) comowww.elprofe.orgestán cubiertos. - HTTP/2 y HTTP/3: Habilitados automáticamente para todos los dominios en Pages.
Múltiples dominios, un mismo proyecto¶
Puedes apuntar múltiples dominios al mismo proyecto de Pages. Por ejemplo, masterfinanzas.com y masterfinanzas.es pueden servir exactamente el mismo contenido sin duplicar el proyecto ni el código.
10.6 — _redirects y _headers: control total sin servidor¶
La magia de los archivos especiales¶
Cloudflare Pages interpreta dos archivos especiales que debes colocar en el directorio de salida del build. Piénsalos como las "instrucciones de tráfico" de tu sitio: le dices a Cloudflare exactamente cómo manejar cada URL antes de que llegue al usuario.
El archivo _redirects¶
La sintaxis básica es minimalista y legible:
Ejemplos para elprofe.org:
# Redirección simple de una página renombrada
/cursos-gratuitos /cursos/gratuitos 301
# Redirección del blog viejo al nuevo
/blog/* /articulos/:splat 301
# Redirigir www al dominio apex
https://www.elprofe.org/* https://elprofe.org/:splat 301
# SPA fallback: todas las rutas no encontradas van al index
/* /index.html 200
# Redirección temporal durante mantenimiento
/admin /mantenimiento.html 302
# Proxying hacia una API externa (invisible al usuario)
/api/v1/* https://api.elprofe.org/:splat 200
El código 200 es especial: a diferencia de una redirección (301/302), un código 200 en _redirects hace un rewrite o proxy. La URL en el navegador no cambia, pero Cloudflare sirve el contenido de la URL de destino. El uso más común es el fallback para Single Page Applications (SPAs):
Esta línea le dice a Cloudflare: "Si no encuentras un archivo para esta ruta, sirve index.html con código 200". Esto es esencial para que el router de React, Vue o cualquier SPA funcione correctamente cuando el usuario recarga una página o accede directamente a una URL interna.
Wildcards y splats:
# * captura todo el segmento de ruta
/blog/* /articulos/:splat 301
# Ejemplo:
# /blog/introduccion-a-python → /articulos/introduccion-a-python
Límites del archivo _redirects:
- 2,000 reglas estáticas (sin wildcards)
- 100 reglas dinámicas (con wildcards)
- Las reglas se evalúan en orden; la primera que coincide gana
El archivo _headers¶
Los encabezados HTTP son una capa fundamental de seguridad. Con _headers, puedes configurarlos precisamente sin ningún servidor.
La sintaxis usa un sistema de secciones:
Configuración de seguridad para elprofe.org:
# Aplicar headers de seguridad a todo el sitio
/*
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
# Permitir CORS solo para la API pública
/api/*
Access-Control-Allow-Origin: https://elprofe.org
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
# Cacheo agresivo para assets estáticos con hash en el nombre
/assets/*
Cache-Control: public, max-age=31536000, immutable
# Sin caché para el HTML principal (siempre fresco)
/*.html
Cache-Control: no-cache, no-store, must-revalidate
Por qué esto importa: el caso de seguridad¶
Pensemos en masterfinanzas.com, una plataforma financiera. Los usuarios ingresan datos sensibles. Sin los encabezados correctos:
X-Frame-Options: DENY— sin esto, un sitio malicioso podría embebermasterfinanzas.comen un<iframe>y hacer clickjacking.X-Content-Type-Options: nosniff— sin esto, un navegador podría adivinar el tipo MIME de un archivo, abriendo vectores de XSS.Content-Security-Policy— sin esto, un script inyectado podría cargar recursos desde dominios maliciosos.
Ninguno de estos controles requiere un servidor. Viven en un archivo de texto en tu repositorio. Son auditables, versionables y completamente gratuitos.
┌───────────────────────────────────────────────────────────────────────┐
│ ESTRUCTURA DE ARCHIVOS ESPECIALES EN EL REPO │
│ │
│ elprofe-org/ │
│ ├── src/ │
│ │ ├── pages/ │
│ │ └── components/ │
│ ├── public/ ← archivos copiados al build output │
│ │ ├── _redirects ← reglas de redirección │
│ │ ├── _headers ← cabeceras HTTP │
│ │ ├── robots.txt │
│ │ └── sitemap.xml │
│ ├── functions/ ← Pages Functions │
│ │ ├── api/ │
│ │ │ ├── stats.js │
│ │ │ └── contact.js │
│ │ └── _middleware.js │
│ ├── astro.config.mjs │
│ └── package.json │
└───────────────────────────────────────────────────────────────────────┘
10.7 — Cloudflare Pages Functions: el edge dentro de tu proyecto¶
De estático a full-stack¶
Pages Functions elimina la fricción de tener un backend separado. Las funciones viven en el directorio /functions/ de tu repositorio, se despliegan automáticamente junto con el sitio estático, y se ejecutan en el mismo edge donde se sirven los archivos.
Cómo funciona el enrutamiento de Functions¶
Pages Functions usa un sistema de enrutamiento basado en la estructura de archivos:
functions/
├── api/
│ ├── stats.js → GET /api/stats
│ ├── contact.js → POST /api/contact
│ └── cursos/
│ └── [id].js → /api/cursos/:id (ruta dinámica)
├── auth/
│ ├── login.js → /auth/login
│ └── logout.js → /auth/logout
└── _middleware.js → aplica a todas las rutas
Cada archivo exporta un handler que recibe un objeto context con la solicitud HTTP, las variables de entorno y acceso a los bindings de Cloudflare.
Tu primera Pages Function¶
Para elprofe.org, un endpoint que devuelve estadísticas básicas del sitio. Creamos functions/api/stats.js:
// functions/api/stats.js
// Disponible en: GET /api/stats
export async function onRequestGet(context) {
const { request, env } = context;
// Leer datos de Workers KV (almacenamiento clave-valor en el edge)
const visitas = await env.STATS_KV.get('total_visitas') || '0';
const ultimaActualizacion = new Date().toISOString();
const data = {
visitas: parseInt(visitas),
ultima_actualizacion: ultimaActualizacion,
region: request.cf?.colo || 'desconocida',
pais: request.cf?.country || 'desconocido',
};
return new Response(JSON.stringify(data), {
headers: {
'Content-Type': 'application/json',
'Cache-Control': 'no-store',
},
});
}
Middleware: lógica transversal¶
El archivo _middleware.js se ejecuta antes de cualquier función o página:
// functions/_middleware.js
export async function onRequest(context) {
const { request, next, env } = context;
const url = new URL(request.url);
// Proteger rutas de administración con Basic Auth
if (url.pathname.startsWith('/admin')) {
const authHeader = request.headers.get('Authorization');
if (!authHeader || !isValidAuth(authHeader, env)) {
return new Response('No autorizado', {
status: 401,
headers: { 'WWW-Authenticate': 'Basic realm="elprofe.org Admin"' },
});
}
}
// Agregar header de tiempo de respuesta
const start = Date.now();
const response = await next();
const duration = Date.now() - start;
const newResponse = new Response(response.body, response);
newResponse.headers.set('X-Response-Time', `${duration}ms`);
return newResponse;
}
function isValidAuth(header, env) {
const encoded = header.replace('Basic ', '');
const decoded = atob(encoded);
const [user, pass] = decoded.split(':');
return user === env.ADMIN_USER && pass === env.ADMIN_PASS;
}
Rutas dinámicas y parámetros¶
Para elprofe.org/api/cursos/:id, el archivo functions/api/cursos/[id].js:
// functions/api/cursos/[id].js
export async function onRequestGet({ params, env }) {
const { id } = params;
const curso = await env.CURSOS_KV.get(`curso:${id}`, { type: 'json' });
if (!curso) {
return new Response(JSON.stringify({ error: 'Curso no encontrado' }), {
status: 404,
headers: { 'Content-Type': 'application/json' },
});
}
return Response.json(curso);
}
Bindings disponibles en Pages Functions¶
┌─────────────────────────────────────────────────────────────────────┐
│ BINDINGS DISPONIBLES EN PAGES FUNCTIONS │
├────────────────────┬────────────────────────────────────────────────┤
│ Binding │ Descripción │
├────────────────────┼────────────────────────────────────────────────┤
│ Workers KV │ Almacenamiento clave-valor distribuido │
│ D1 (SQLite) │ Base de datos SQL en el edge │
│ R2 │ Almacenamiento de objetos (como S3) │
│ Durable Objects │ Estado persistente con consistencia fuerte │
│ AI │ Workers AI (inferencia en el edge) │
│ Service Bindings │ Llamar a otros Workers desde una Function │
│ Queue │ Colas de mensajes asíncronas │
│ Vectorize │ Base de datos vectorial para búsqueda semántica│
└────────────────────┴────────────────────────────────────────────────┘
Pages Functions vs. Workers: ¿cuándo usar cuál?¶
┌─────────────────────────────────────────────────────────────────────────┐
│ PAGES FUNCTIONS vs. WORKERS │
├─────────────────────────────────┬───────────────────────────────────────┤
│ Pages Functions │ Workers │
├─────────────────────────────────┼───────────────────────────────────────┤
│ ✓ API ligada al sitio estático │ ✓ Servicio standalone │
│ ✓ Deploy automático con el repo │ ✓ Cron Triggers (tareas programadas) │
│ ✓ Enrutamiento por archivos │ ✓ Durable Objects propios │
│ ✓ Ideal para BFF (Backend for │ ✓ Rate Limiting avanzado │
│ Frontend) │ ✓ Queues, Pipelines │
│ ✓ Menos configuración inicial │ ✓ Funcionalidades de vanguardia │
│ │ (llegan primero a Workers) │
├─────────────────────────────────┴───────────────────────────────────────┤
│ La convergencia 2025-2026: Cloudflare está integrando Pages │
│ como una capa de deploy sobre Workers. A largo plazo, la │
│ distinción entre los dos disminuirá. │
└─────────────────────────────────────────────────────────────────────────┘
El Capítulo 11 explora Workers en profundidad con el ejemplo de nlink.uk, donde necesitamos capacidades que van más allá de Pages Functions: Cron Triggers para limpiar URLs expiradas y Durable Objects para estadísticas en tiempo real.
10.8 — Preview deployments y colaboración en equipo¶
Cada rama, su propio universo¶
Cada push a cualquier rama que no sea la de producción genera automáticamente un deploy en una URL única:
Rama: feature/nueva-seccion-cursos
URL de preview: https://feature-nueva-seccion-cursos.elprofe-org.pages.dev
Rama: fix/error-formulario-contacto
URL de preview: https://fix-error-formulario-contacto.elprofe-org.pages.dev
Rama: redesign/portada-2026
URL de preview: https://redesign-portada-2026.elprofe-org.pages.dev
Las URLs de preview son públicas (cualquier persona con la URL puede verlas), protegibles (puedes activar Cloudflare Access), persistentes (cada deploy queda disponible indefinidamente) y funcionales al 100% (incluyen Pages Functions y variables de entorno de "preview").
El flujo de trabajo real¶
┌──────────────────────────────────────────────────────────────────────────┐
│ FLUJO DE TRABAJO CON PREVIEW DEPLOYMENTS │
│ │
│ Desarrollador A Desarrollador B Diseñador │
│ ┌─────────────────┐ ┌───────────────┐ ┌──────────────┐ │
│ │ feature/login │ │ fix/mobile │ │ (solo review)│ │
│ └────────┬────────┘ └───────┬───────┘ └──────┬───────┘ │
│ │ git push │ git push │ │
│ ▼ ▼ │ │
│ ┌─────────────────────────────────────────────────────────┐ │ │
│ │ Cloudflare Pages Build System │ │ │
│ └─────────────────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ ▼ ▼ │ │
│ preview-A.elprofe-org.pages.dev preview-B.elprofe-org.pages.dev │
│ │ │ │ │
│ └──────────────────────────────┼───────────────────┘ │
│ │ revisión y aprobación │
│ ▼ │
│ PR merge → main → elprofe.org │
└──────────────────────────────────────────────────────────────────────────┘
Comentarios automáticos en PRs¶
Cloudflare Pages comenta automáticamente en los pull requests de GitHub con el enlace al preview deployment. Cuando el equipo de elprofe.org abre un PR, el bot de Cloudflare agrega:
✅ Cloudflare Pages — Deploy preview listo para este pull request
| URL de preview | Estado | Actualizado |
|---|---|---|
| https://abc123.elprofe-org.pages.dev | Exitoso | hace 2 minutos |
Esto elimina la fricción habitual de los servidores de staging manuales. El staging es automático, vive en la nube y tiene la URL en el mismo PR.
Rollback instantáneo¶
Si el deploy en producción introduce un bug crítico en elprofe.org:
- Ir a "Workers & Pages" → proyecto → "Deployments".
- Encontrar el último deploy estable.
- Hacer clic en "Rollback to this deployment".
En menos de 60 segundos, elprofe.org sirve la versión anterior sin necesidad de revertir código ni esperar un nuevo build.
10.9 — Comparativa: Pages vs Vercel vs Netlify vs Firebase Hosting¶
Tabla comparativa general¶
| Característica | Cloudflare Pages | Vercel | Netlify | Firebase Hosting |
|---|---|---|---|---|
| Plan gratuito | Sí (muy generoso) | Sí (solo personal) | Sí (limitado) | Sí (limitado) |
| Uso comercial gratuito | ✓ Sí | ✗ No (requiere Pro) | ✓ Sí (con límites) | ✓ Sí (con límites) |
| Red CDN | 330+ PoPs propios | ~100 PoPs (AWS-based) | ~100 PoPs (AWS-based) | Google Cloud CDN |
| Builds gratuitos/mes | 500 | 100 GB-horas | 300 minutos | No aplica (solo deploy) |
| Funciones serverless | Pages Functions (edge) | Edge/Lambda Functions | Edge/Lambda Functions | Cloud Functions (regional) |
| SPA routing | ✓ _redirects (200) |
✓ vercel.json |
✓ _redirects |
✓ firebase.json |
| Dominios personalizados | 100 (free) / 250 (paid) | Ilimitado (Pro) | Ilimitado | Ilimitado |
| Preview deployments | ✓ Todas las ramas | ✓ Todas las ramas | ✓ Todas las ramas | Limitado |
| Ancho de banda | Ilimitado | 100 GB/mes (free) | 100 GB/mes (free) | 360 MB/día (free) |
Comparativa de costo a 2 millones de visitas/mes (equipo de 3)¶
┌─────────────────────────────────────────────────────────────────────────┐
│ COSTO MENSUAL A 2M VISITAS — EQUIPO DE 3 PERSONAS │
│ │
│ Cloudflare Pages (Free) ████ $0/mes │
│ Cloudflare Pages (Paid) ████ $5/mes │
│ Firebase Hosting (Blaze) ████ ~$8/mes │
│ Netlify Pro (x3) ████████████████ $57/mes │
│ Vercel Pro (x3) ████████████████████ $70/mes │
│ │
│ * Cloudflare Pages: ancho de banda ilimitado. Sin costo por visitas. │
│ * Vercel/Netlify: costo por usuario del equipo, no por tráfico. │
└─────────────────────────────────────────────────────────────────────────┘
| Plataforma | Costo mensual (equipo de 3, 2M visitas) |
|---|---|
| Cloudflare Pages (Free) | $0 |
| Cloudflare Pages (Workers Paid) | $5 |
| Firebase Hosting Blaze | ~$8 (variable según uso) |
| Netlify Pro | ~$57 ($19/usuario × 3) |
| Vercel Pro | ~$70 ($20/usuario × 3 + extras) |
Cuándo elegir cada plataforma¶
Cloudflare Pages es la mejor opción si: - Quieres ancho de banda ilimitado sin costo. - Tu proyecto es comercial y no puedes usar el plan gratuito de Vercel. - Necesitas la red CDN más grande y performante disponible. - Ya usas Cloudflare para DNS y otras herramientas. - Construyes aplicaciones con múltiples proyectos (el plan $5 cubre todo).
Vercel es la mejor opción si: - Usas Next.js y quieres la integración más profunda posible. - Tu equipo de una persona trabaja en proyectos personales. - Valoras las analytics y métricas de performance integradas.
Netlify es la mejor opción si: - Tienes proyectos con mucho contenido generado (Netlify CMS / Decap CMS). - Necesitas formularios manejados sin backend (Netlify Forms). - Tu equipo ya tiene experiencia con su ecosistema.
Firebase Hosting es la mejor opción si: - Construyes aplicaciones en el ecosistema de Google (Firestore, Authentication). - Usas Flutter Web.
10.10 — Límites, planes y cuándo escalar¶
El plan gratuito es genuinamente generoso¶
┌──────────────────────────────────────────────────────────────────────┐
│ PLAN FREE — CLOUDFLARE PAGES (Abril 2026) │
├─────────────────────────────────┬────────────────────────────────────┤
│ Característica │ Límite │
├─────────────────────────────────┼────────────────────────────────────┤
│ Builds / mes │ 500 │
│ Builds concurrentes │ 1 │
│ Archivos / sitio │ 20,000 (máx 25 MB por archivo) │
│ Ancho de banda │ Ilimitado ✓ │
│ Dominios personalizados │ 100 por proyecto │
│ Proyectos │ Ilimitados ✓ │
│ Pages Functions │ 100,000 solicitudes/día │
│ Workers KV │ Incluido (límites plan Free KV) │
│ Preview deployments │ Ilimitados ✓ │
│ Miembros de equipo │ Ilimitados ✓ │
└─────────────────────────────────┴────────────────────────────────────┘
El plan Workers Paid ($5/mes)¶
┌──────────────────────────────────────────────────────────────────────┐
│ WORKERS PAID ($5/MES) — CLOUDFLARE PAGES (Abril 2026) │
├─────────────────────────────────┬────────────────────────────────────┤
│ Característica │ Límite │
├─────────────────────────────────┼────────────────────────────────────┤
│ Builds / mes │ 5,000 │
│ Builds concurrentes │ 5 │
│ Archivos / sitio │ 100,000 (requiere │
│ │ PAGES_WRANGLER_MAJOR_VERSION=4) │
│ Ancho de banda │ Ilimitado ✓ │
│ Dominios personalizados │ 250 por proyecto │
│ Functions │ 10M solicitudes/mes incluidas │
│ │ luego $0.50/millón │
└─────────────────────────────────┴────────────────────────────────────┘
Nota técnica: El límite de 100,000 archivos en el plan Paid requiere configurar
PAGES_WRANGLER_MAJOR_VERSION=4. Sin esta variable, el límite aplicado sigue siendo 20,000 aunque tengas el plan Paid.
¿Cuándo escalar al plan Paid?¶
Los casos más comunes son:
- Equipos con desarrollo activo: Si tu equipo hace múltiples deploys al día y se acerca a los 500 builds/mes.
- Sitios de gran volumen con muchos archivos: Frameworks que generan muchos archivos pequeños pueden superar los 20,000.
- APIs con tráfico alto: Si superas las 100,000 solicitudes de Functions por día.
- Builds concurrentes: Un equipo grande que hace deploy desde múltiples ramas simultáneamente.
Cuándo migrar a Workers en lugar de escalar Pages¶
Hay situaciones donde la solución correcta no es pagar más por Pages sino migrar la lógica a Workers:
- Cron jobs:
nlink.uknecesita limpiar URLs expiradas cada hora. Pages Functions no tiene Cron Triggers; Workers sí. - Durable Objects: Estado compartido y transacciones consistentes entre múltiples solicitudes simultáneas.
- Queues: Procesamiento asíncrono de trabajo en background.
- Lógica desacoplada del frontend: Una API que sirve a múltiples clientes (web, móvil, otras APIs).
Buenas prácticas¶
-
Versiona siempre
_redirectsy_headersen el repositorio. No los gestiones manualmente en el panel. Si están en el repo, son auditables, revisables en PRs y se aplican automáticamente en cada deploy. -
Usa variables de entorno para todas las URLs de servicios externos, incluso las que no son secretas.
PUBLIC_API_URL=https://api.elprofe.orges mucho más mantenible que una cadena hardcodeada en 50 componentes. -
Separa las variables de build y runtime. Las variables de build se incrustan en el bundle JavaScript durante el build. Las variables de runtime en Pages Functions nunca llegan al cliente. Confundirlas es un vector de exposición de secretos.
-
Activa preview deployments para todas las ramas de feature pero desactívalos para branches como
chore/*odocs/*que no requieren revisión visual. -
Configura
Cache-Controlen_headerspara assets estáticos. Los archivos con hash en el nombre pueden tenermax-age=31536000, immutable. El HTML principal debe tenerno-cache. Esta diferencia puede reducir drásticamente el ancho de banda y mejorar la experiencia del usuario. -
Usa el patrón de Direct Upload para builds complejos. Si tu pipeline de build requiere recursos especiales, construye localmente o en GitHub Actions y usa
wrangler pages deploypara subir solo los artefactos. -
Monitorea el uso de Functions con Cloudflare Analytics. El plan Free tiene 100,000 solicitudes/día. Si estás cerca del límite, considera cachear respuestas de Functions con la Cache API de Cloudflare o mover operaciones frecuentes a KV.
-
Implementa los headers de seguridad esenciales desde el inicio. Un buen punto de partida para cualquier proyecto:
-
Para SPAs, siempre incluye el fallback
/* /index.html 200en_redirects. Sin esta línea, recargar cualquier ruta interna de la aplicación devolverá un 404. -
Mantén el build reproducible. Usa
package-lock.jsonobun.lockpara fijar las versiones de dependencias. Un build que falla en Cloudflare por una dependencia que actualizó su API es un problema innecesario. -
Configura notificaciones de deploy fallido. Cloudflare puede enviar webhooks o emails cuando un build falla. En producción, saber de inmediato que algo salió mal vale mucho.
-
Documenta las variables de entorno en el repositorio. Un archivo
.env.examplecon las variables necesarias (sin sus valores reales) ahorra horas a cada nuevo miembro del equipo.
Errores comunes¶
Error 1: El SPA muestra 404 al recargar rutas internas
- Síntoma: elprofe.org/cursos/matematicas muestra "404 - Not Found" al recargar.
- Causa: Cloudflare busca un archivo cursos/matematicas/index.html que no existe.
- Solución: Agregar al archivo _redirects: /* /index.html 200
Error 2: Variables de entorno no disponibles en el frontend
- Síntoma: process.env.PUBLIC_API_URL es undefined en el navegador.
- Causa: Para Vite, la variable debe tener el prefijo VITE_. Para Next.js, el prefijo es NEXT_PUBLIC_. Sin el prefijo correcto, la variable solo existe en el build, no en el bundle final.
- Solución: Renombrar PUBLIC_API_URL a VITE_API_URL (Vite) o NEXT_PUBLIC_API_URL (Next.js).
Error 3: Build falla con "Error: command not found: hugo"
- Síntoma: El build de un sitio Hugo falla con este mensaje.
- Causa: Cloudflare Pages no detectó automáticamente el framework.
- Solución: Seleccionar "Hugo" como framework preset en la configuración. Si necesitas una versión específica, agregar HUGO_VERSION=0.147.1 como variable de entorno.
Error 4: La redirección en _redirects no funciona
- Síntoma: La regla está en el archivo pero las URLs no redirigen.
- Causa más común: El archivo _redirects debe estar en el directorio de salida del build, no en la raíz del repositorio. En un proyecto Astro, debe estar en public/_redirects.
- Solución: Verificar la ubicación del archivo según el framework usado.
Error 5: Headers CORS incorrectos en Pages Functions
- Síntoma: El frontend no puede hacer peticiones a /api/* con error "blocked by CORS policy".
- Solución: Las Functions deben incluir los headers CORS en cada respuesta, incluyendo las solicitudes OPTIONS (preflight):
const corsHeaders = {
'Access-Control-Allow-Origin': 'https://elprofe.org',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type',
};
export async function onRequestOptions() {
return new Response(null, { status: 204, headers: corsHeaders });
}
Error 6: El límite de 20,000 archivos se alcanza con Gatsby o Eleventy
- Síntoma: El build falla con "Too many files" en sitios con mucho contenido.
- Solución A: Actualizar al plan Workers Paid y configurar PAGES_WRANGLER_MAJOR_VERSION=4.
- Solución B: Revisar si hay archivos innecesarios en el output.
Error 7: Deploy lento por falta de caché de dependencias
- Síntoma: Cada build tarda 5-10 minutos instalando node_modules.
- Causa: Si el archivo de lock no está commiteado, Cloudflare no puede cachear las dependencias.
- Solución: Asegurarse de que package-lock.json, yarn.lock o bun.lock esté incluido en el repositorio.
Error 8: Pages Function responde con 500 sin logs claros
- Síntoma: La función devuelve error 500 intermitentemente.
- Causa más común: Excepciones no capturadas fuera de un bloque try/catch.
- Solución: Envolver toda la lógica en try/catch y usar console.error(). Los logs son visibles en "Workers & Pages" → proyecto → "Real-time logs".
Error 9: Dominio personalizado muestra "Too many redirects" - Síntoma: Al acceder al dominio personalizado, el navegador muestra un bucle de redirecciones. - Causa: El modo SSL de Cloudflare está en "Flexible". Con "Flexible", Cloudflare conecta al servidor de origen por HTTP, pero si el origen redirige a HTTPS, se crea un bucle. - Solución: Cambiar SSL/TLS a "Full" o "Full (Strict)" en la configuración del dominio.
Error 10: Next.js con @cloudflare/next-on-pages falla por APIs de Node.js
- Síntoma: Funcionalidades específicas de Next.js fallan con errores de runtime.
- Causa: El edge runtime de Cloudflare no implementa todas las APIs de Node.js.
- Solución: Agregar export const runtime = 'edge' a las rutas que deben funcionar en Cloudflare, y revisar la lista de compatibilidad en la documentación oficial.
Curiosidades y datos que pocos conocen¶
El build no es en us-east-1. A diferencia de Vercel y Netlify, que corren sus builds en AWS, Cloudflare corre sus builds en su propia infraestructura. Esto significa que si tu build descarga dependencias de registros npm o pip, lo hace desde servidores de Cloudflare con excelente conectividad global.
El archivo _redirects de Netlify es intencionalmente compatible. Cuando Cloudflare diseñó este sistema, eligió mantener la misma sintaxis que Netlify para facilitar las migraciones. Un archivo _redirects de Netlify funciona en Pages sin modificaciones en la mayoría de los casos.
Las Pages Functions son Workers disfrazados. Internamente, cuando Pages despliega un proyecto con Functions, crea automáticamente un Worker de Cloudflare que sirve tanto los archivos estáticos como las funciones. La URL *.pages.dev es simplemente un Worker que decide si responder con un archivo del KV storage o ejecutar la función correspondiente.
El ancho de banda realmente es ilimitado. En la industria, "ilimitado" suele ser una promesa de marketing con asteriscos. En Cloudflare Pages, el ancho de banda es genuinamente ilimitado porque Cloudflare opera su propio backbone de red. No hay un costo de egress como en AWS o GCP que tengan que trasladarte.
Puedes usar Pages como un CDN personal. Nada te impide crear un proyecto de Pages que solo contenga imágenes, fuentes o videos. Cloudflare los servirá desde su CDN global con compresión automática (Brotli y gzip) y HTTP/3, completamente gratis.
El historial de deploys es eterno. Cada deploy exitoso permanece disponible por su URL única para siempre (o al menos mientras exista el proyecto). Puedes compartir un enlace a una versión específica de tu sitio y ese enlace nunca dejará de funcionar.
Las Pages Functions pueden acceder a request.cf, un objeto especial de Cloudflare que contiene metadatos de la solicitud: país, ciudad, región, proveedor de internet y hasta el índice de calidad de la conexión. Todo esto sin pagar por un servicio de geolocalización adicional.
El nombre del proyecto determina la URL de pages.dev para siempre. Una vez que creas el proyecto con el nombre elprofe-org, la URL elprofe-org.pages.dev es tuya. Si renombras el proyecto, la URL original deja de funcionar. Es una decisión que no se puede revertir fácilmente, por lo que conviene elegir bien el nombre desde el inicio.
Resumen del capítulo¶
Cloudflare Pages representa la maduración del modelo JAMstack: sitios construidos de antemano, servidos desde una CDN global, con la posibilidad de agregar lógica de backend en el edge cuando se necesita. Lo que diferencia a Pages de otras plataformas similares es la escala de la infraestructura subyacente —la misma red de 330+ PoPs que maneja una fracción significativa del tráfico de internet— y el precio, que hace que el ancho de banda ilimitado y el plan gratuito genuinamente útil sean posibles sin subsidios de inversores de riesgo.
El pipeline de publicación es simple en su descripción —conectar repositorio, configurar build, hacer push— pero sofisticado en su implementación: deploys diferenciales que solo actualizan los archivos que cambiaron, propagación global automática, invalidación de caché instantánea y un sistema de preview deployments que transforma la colaboración en equipo.
El sistema de build v3 soporta todos los frameworks relevantes del ecosistema JavaScript moderno, Python, Go y Bun, con Node.js 22 como runtime predeterminado. Las variables de entorno automáticas (CF_PAGES_BRANCH, CF_PAGES_URL, etc.) permiten adaptar el comportamiento del build y del sitio según el entorno, sin hardcodear valores.
Los archivos _redirects y _headers son herramientas deceptivamente simples pero extremadamente poderosas. Con menos de 20 líneas de texto plano en _headers, un sitio puede implementar los controles de seguridad que muchas organizaciones pagan por gestionar con WAFs dedicados. El archivo _redirects, con su soporte de wildcards, splats y el código 200 para reescrituras, resuelve la mayoría de los problemas de routing sin necesidad de ningún servidor.
Pages Functions extiende el modelo a full-stack: funciones JavaScript que se ejecutan en el edge junto al sitio estático, con acceso a Workers KV, D1, R2, AI y otros servicios de Cloudflare. El enrutamiento por estructura de archivos hace que agregar una API a un sitio estático sea tan simple como crear un archivo en functions/api/. El middleware global permite implementar autenticación, logging y modificación de headers de manera centralizada.
Los preview deployments son una de las características que más impacto tiene en la productividad del equipo: cada rama de Git tiene su propia URL pública, completamente funcional, con variables de entorno de preview. El ciclo de revisión —desarrolla en una rama, comparte el enlace de preview, obtén aprobación, merge a producción— es más rápido y confiable que cualquier servidor de staging manual.
En la comparativa de plataformas, la ventaja de Cloudflare Pages se hace más clara a medida que el proyecto crece: ancho de banda ilimitado donde competidores cobran por gigabyte, $5/mes para un equipo completo donde competidores cobran $20+ por usuario, y la red CDN más grande del mercado. Las plataformas alternativas tienen ventajas específicas —Vercel para Next.js, Netlify para su ecosistema de CMS y Forms, Firebase para el stack de Google— pero para proyectos nuevos sin compromisos previos, Pages es difícil de superar en la relación capacidad/costo.
Los límites del plan gratuito (500 builds/mes, 20,000 archivos, 100,000 solicitudes de Functions por día) son generosos para proyectos pequeños y medianos, pero deben monitorearse en proyectos con equipos activos o alto tráfico de API. El plan Workers Paid por $5/mes resuelve la mayoría de los casos de uso. Solo cuando se necesitan características como Cron Triggers, Queues, o Durable Objects propios tiene sentido migrar la lógica a Workers independientes.
La evolución de Cloudflare Pages hacia una integración más profunda con Workers —una tendencia clara en 2025-2026— es una señal positiva: la plataforma no está estancada sino convergiendo hacia una arquitectura más potente, donde la distinción entre "sitio estático" y "aplicación serverless" desaparece en favor de un modelo unificado de despliegue en el edge.
Glosario¶
Build system: El sistema que toma el código fuente de tu proyecto y lo transforma en los archivos listos para servir al usuario. Instala dependencias, ejecuta el compilador o bundler, y produce el directorio de salida.
Bundle: El archivo o conjunto de archivos JavaScript producidos por un bundler (Vite, Webpack, esbuild) que combinan todos los módulos de tu aplicación en uno o pocos archivos optimizados para el navegador.
Caché de CDN: Copia de los archivos de tu sitio almacenada en los servidores de la CDN (en este caso, los PoPs de Cloudflare). Cuando un usuario solicita una página, el servidor de caché más cercano responde sin necesidad de consultar el servidor de origen.
Deploy diferencial: Técnica donde solo se suben al servidor los archivos que cambiaron respecto a la versión anterior, en lugar de subir todos los archivos del sitio. Reduce el tiempo de deploy y el uso de ancho de banda.
Deploy de preview: Una versión del sitio generada automáticamente para cada rama de Git que no es la de producción, disponible en una URL única. Permite revisar cambios antes de publicarlos en producción.
Direct Upload: Método de deploy donde los archivos ya construidos se suben directamente a Cloudflare Pages usando Wrangler, sin pasar por el sistema de build de Pages. Útil cuando el build ocurre en otro entorno.
Edge computing: Modelo de computación donde el código se ejecuta en servidores distribuidos geográficamente cerca del usuario, en lugar de en un data center centralizado. Cloudflare Pages Functions es edge computing.
Framework preset: Configuración predefinida que Cloudflare Pages aplica automáticamente cuando detecta un framework específico, pre-rellenando el comando de build y el directorio de salida.
JAMstack: Arquitectura de aplicaciones web basada en JavaScript, APIs y Markup pregenerado. El sitio se construye estáticamente, se sirve desde una CDN y usa APIs para la lógica dinámica.
Pages Function: Función serverless que vive en el directorio functions/ de tu proyecto de Cloudflare Pages. Se despliega automáticamente junto al sitio estático y se ejecuta en el edge de Cloudflare.
Pipeline de CI/CD: Continuous Integration / Continuous Deployment. El proceso automatizado que toma cambios de código, los construye, los prueba y los despliega. En Pages, el pipeline se activa con cada push a Git.
PoP (Point of Presence): Localización física de servidores de Cloudflare distribuidos por el mundo (330+ ciudades). Los archivos de tu sitio se almacenan en caché en cada PoP para ser servidos con mínima latencia.
Rewrite (reescritura): Cuando el servidor sirve el contenido de una URL diferente a la que el usuario solicitó, sin cambiar la URL en el navegador. Se logra con el código 200 en _redirects.
Rollback: Proceso de revertir un sitio a una versión anterior de un deploy. En Pages, se hace con un clic desde el historial de deploys.
Runtime de Workers: El entorno de ejecución JavaScript de Cloudflare, que implementa las Web Standards APIs pero no todas las APIs de Node.js. Es donde se ejecutan las Pages Functions.
Splat (:splat): En la sintaxis de _redirects, :splat captura la parte de la URL que coincidió con el wildcard *. Se usa en la URL de destino para preservar esa porción de la ruta.
SSL/TLS: El protocolo criptográfico que habilita HTTPS. Cloudflare Pages gestiona automáticamente los certificados TLS para todos los dominios personalizados.
Variable de entorno: Par clave-valor disponible para el proceso de build o para las Pages Functions en tiempo de ejecución. Se usa para configurar el comportamiento del proyecto sin modificar el código fuente.
Wrangler: La herramienta de línea de comandos oficial de Cloudflare para desarrollar y desplegar Workers y Pages. Permite hacer deploy, administrar variables de entorno y simular el entorno de Pages localmente.
Workers KV: Key-Value store de Cloudflare, distribuido globalmente en el edge. Disponible como binding en Pages Functions para almacenar y recuperar datos con muy baja latencia.
20 preguntas de autoevaluación¶
-
¿Cuál es el límite de builds por mes en el plan gratuito de Cloudflare Pages?
-
¿Qué variable de entorno automática contiene el nombre de la rama de Git que disparó el build?
-
¿En qué directorio del repositorio deben colocarse los archivos de Pages Functions?
-
¿Qué código HTTP se usa en
_redirectspara hacer un rewrite (servir contenido de otra URL sin cambiar la URL del navegador)? -
¿Cuál es el directorio de salida correcto para un proyecto Next.js configurado con
@cloudflare/next-on-pages? -
¿Cuántos dominios personalizados permite el plan gratuito por proyecto?
-
¿Qué archivo especial se usa para configurar cabeceras HTTP personalizadas en Cloudflare Pages?
-
¿Cuál es la versión de Node.js disponible en el Build System v3 de Cloudflare Pages?
-
Nombra dos limitaciones de Pages Functions que sí están disponibles en Workers independientes.
-
¿Qué significa el símbolo
:splaten la sintaxis de_redirects? -
¿Cuál es la diferencia entre una variable de entorno de "Build" y una de "Runtime" en Pages?
-
¿En qué lugar del repositorio debe colocarse el archivo
_redirectspara un proyecto Astro? -
¿Cuántas solicitudes de Pages Functions por día incluye el plan gratuito?
-
¿Qué variable de entorno hay que configurar para aprovechar el límite de 100,000 archivos en el plan Workers Paid?
-
¿Por qué ocurre el bucle de redirecciones "Too many redirects" al configurar un dominio personalizado?
-
¿Cuál es el costo mensual del plan Workers Paid que incluye Pages en 2026?
-
¿Qué es un deploy diferencial y por qué es importante?
-
¿Cuál plataforma —Vercel, Netlify o Cloudflare Pages— ofrece ancho de banda ilimitado en su plan gratuito?
-
¿Para qué sirve el archivo
_middleware.jsen el directoriofunctions/? -
¿Cómo se llama el comando de CLI para hacer un Direct Upload de archivos a Cloudflare Pages?
Respuestas:
-
500 builds por mes.
-
CF_PAGES_BRANCH -
En el directorio
/functions/en la raíz del repositorio. -
Código HTTP 200.
-
.vercel/output/static -
100 dominios personalizados por proyecto.
-
El archivo
_headers. -
Node.js 22.16.0
-
Cualquier dos de: Cron Triggers (tareas programadas), Durable Objects propios, Queues, Rate Limiting avanzado. Las nuevas funcionalidades de Cloudflare llegan primero a Workers.
-
:splatcaptura en la URL de destino la parte de la URL que coincidió con el wildcard*en la URL fuente. -
Las variables de Build solo están disponibles durante el proceso de construcción del sitio (se incrustan en el bundle). Las variables de Runtime están disponibles en Pages Functions cuando se ejecutan solicitudes de usuarios; nunca llegan al código del cliente.
-
En el directorio
public/_redirects(que Astro copia automáticamente al directoriodist/durante el build). -
100,000 solicitudes por día.
-
PAGES_WRANGLER_MAJOR_VERSION=4 -
Ocurre cuando el modo SSL está en "Flexible". Cloudflare conecta al origen por HTTP, el origen redirige a HTTPS, y se crea un bucle infinito. La solución es cambiar SSL a "Full" o "Full (Strict)".
-
$5 por mes.
-
Un deploy diferencial solo sube los archivos que cambiaron desde el deploy anterior. Reduce el tiempo de deploy y el uso de red.
-
Cloudflare Pages. Vercel y Netlify tienen límite de 100 GB/mes en sus planes gratuitos.
-
_middleware.jscontiene lógica que se ejecuta antes de que cualquier solicitud llegue a las funciones individuales o a los archivos estáticos. Es ideal para autenticación, logging y modificación de headers de manera centralizada. -
npx wrangler pages deploy ./dist --project-name=nombre-del-proyecto
Proyecto práctico¶
Proyecto: Publicar elprofe.org con Cloudflare Pages¶
Este proyecto integra todos los conceptos del capítulo en un flujo de trabajo completo: desde la configuración del repositorio hasta el dominio personalizado en producción.
Objetivo: Publicar la plataforma educativa elprofe.org usando Cloudflare Pages con Astro, incluyendo un dominio personalizado, reglas de seguridad, redirecciones y una Function de backend.
Prerequisitos:
- Cuenta de Cloudflare con dominio elprofe.org configurado (Capítulo 9)
- Node.js 22+ instalado localmente
- Cuenta de GitHub
Paso 1: Crear el proyecto Astro¶
npm create astro@latest elprofe-org
# Seleccionar: "A basic, minimal starter"
# Seleccionar: Yes para TypeScript
# Seleccionar: Yes para instalar dependencias
cd elprofe-org
Paso 2: Estructura de carpetas¶
elprofe-org/
├── src/
│ ├── pages/
│ │ ├── index.astro ← Portada
│ │ ├── cursos/
│ │ │ ├── index.astro ← Listado de cursos
│ │ │ └── [slug].astro ← Página de curso individual
│ │ └── contacto.astro
│ ├── components/
│ │ ├── Header.astro
│ │ └── Footer.astro
│ └── layouts/
│ └── Base.astro
├── public/
│ ├── _redirects ← Reglas de redirección
│ ├── _headers ← Cabeceras HTTP
│ ├── robots.txt
│ └── images/
│ └── logo.svg
├── functions/
│ └── api/
│ ├── stats.js ← GET /api/stats
│ └── contacto.js ← POST /api/contacto
├── astro.config.mjs
└── package.json
Paso 3: Configurar _redirects¶
Crea el archivo public/_redirects:
# Redirección www → dominio apex
https://www.elprofe.org/* https://elprofe.org/:splat 301
# URL antigua del blog → nueva sección
/blog/* /articulos/:splat 301
# Alias cortos para cursos populares
/python /cursos/python-desde-cero 302
/javascript /cursos/javascript-moderno 302
/sql /cursos/bases-de-datos-sql 302
# SPA fallback — siempre al final del archivo
/* /index.html 200
Paso 4: Configurar _headers¶
Crea el archivo public/_headers:
# Headers de seguridad para todo el sitio
/*
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
Strict-Transport-Security: max-age=31536000; includeSubDomains
# Assets estáticos con hash → caché agresiva
/_astro/*
Cache-Control: public, max-age=31536000, immutable
# Imágenes → caché de 30 días
/images/*
Cache-Control: public, max-age=2592000
# HTML → siempre fresco
/*.html
Cache-Control: no-cache, must-revalidate
# API → sin caché
/api/*
Cache-Control: no-store
Access-Control-Allow-Origin: https://elprofe.org
Access-Control-Allow-Methods: GET, POST, OPTIONS
Paso 5: Crear las Pages Functions¶
Función de estadísticas (functions/api/stats.js):
// functions/api/stats.js
export async function onRequestGet({ request, env }) {
try {
const currentCount = parseInt(
(await env.STATS_KV?.get('visitas_totales')) || '0'
);
await env.STATS_KV?.put('visitas_totales', String(currentCount + 1));
const stats = {
visitas_totales: currentCount + 1,
timestamp: new Date().toISOString(),
pais: request.cf?.country || 'desconocido',
ciudad: request.cf?.city || 'desconocida',
datacenter: request.cf?.colo || 'desconocido',
};
return Response.json(stats, {
headers: { 'Cache-Control': 'no-store' }
});
} catch (error) {
console.error('Error en /api/stats:', error.message);
return Response.json(
{ error: 'Error interno del servidor' },
{ status: 500 }
);
}
}
Función de contacto (functions/api/contacto.js):
// functions/api/contacto.js
const CORS_HEADERS = {
'Access-Control-Allow-Origin': 'https://elprofe.org',
'Access-Control-Allow-Methods': 'POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type',
};
export async function onRequestOptions() {
return new Response(null, { status: 204, headers: CORS_HEADERS });
}
export async function onRequestPost({ request, env }) {
try {
const body = await request.json();
const { nombre, email, mensaje } = body;
if (!nombre || !email || !mensaje) {
return Response.json(
{ error: 'Todos los campos son requeridos' },
{ status: 400, headers: CORS_HEADERS }
);
}
const key = `contacto:${Date.now()}`;
await env.CONTACTO_KV?.put(key, JSON.stringify({
nombre, email, mensaje,
fecha: new Date().toISOString(),
ip: request.headers.get('CF-Connecting-IP'),
}));
return Response.json(
{ success: true, mensaje: '¡Gracias! Te responderemos pronto.' },
{ status: 200, headers: CORS_HEADERS }
);
} catch (error) {
console.error('Error en /api/contacto:', error.message);
return Response.json(
{ error: 'Error interno del servidor' },
{ status: 500, headers: CORS_HEADERS }
);
}
}
Paso 6: Subir el código a GitHub¶
git init
git add .
git commit -m "feat: setup inicial de elprofe.org con Astro + Pages Functions"
git remote add origin https://github.com/tu-usuario/elprofe-org.git
git branch -M main
git push -u origin main
Paso 7: Crear el proyecto en Cloudflare Pages¶
- Ir a
dash.cloudflare.com→ "Workers & Pages" → "Create application" → "Pages". - Clic en "Connect to Git" y seleccionar el repositorio
elprofe-org. - Configurar el build:
- Framework preset: Astro
- Build command:
npm run build - Build output directory:
dist - Agregar variables de entorno:
- Clic en "Save and Deploy".
Paso 8: Configurar KV Namespaces¶
- En "Workers & Pages" → "KV" → crear namespace
elprofe-statsyelprofe-contacto. - En el proyecto → "Settings" → "Functions" → "KV namespace bindings":
STATS_KV→elprofe-statsCONTACTO_KV→elprofe-contacto- Guarda y redespliega.
Paso 9: Conectar el dominio personalizado¶
- En el proyecto → "Custom domains" → "Set up a custom domain".
- Ingresa
elprofe.org. - Cloudflare crea automáticamente el registro CNAME.
- Repite para
www.elprofe.org. - Verifica que SSL esté en "Full" o "Full (Strict)".
Paso 10: Verificar el deploy¶
# Verificar headers de seguridad
curl -I https://elprofe.org
# Debe mostrar: x-content-type-options: nosniff, x-frame-options: DENY
# Verificar la API de stats
curl https://elprofe.org/api/stats
# {"visitas_totales":1,"timestamp":"2026-06-28T...","pais":"MX",...}
# Verificar la API de contacto
curl -X POST https://elprofe.org/api/contacto \
-H "Content-Type: application/json" \
-d '{"nombre":"Ana","email":"ana@test.com","mensaje":"Hola!"}'
# {"success":true,"mensaje":"¡Gracias! Te responderemos pronto."}
Paso 11: Activar el workflow de preview deployments¶
# Crear una rama de feature
git checkout -b feature/nueva-seccion-testimonios
# ... hacer cambios ...
git add .
git commit -m "feat: agregar sección de testimonios de estudiantes"
git push origin feature/nueva-seccion-testimonios
# Cloudflare Pages comentará en el PR con el enlace de preview
# Revisar, aprobar, hacer merge → deploy automático a elprofe.org
¡Felicidades! elprofe.org está publicado en la red global de Cloudflare, con HTTPS automático, API en el edge, headers de seguridad y un workflow profesional de CI/CD, todo por $0 al mes.
Teaser del siguiente capítulo¶
Capítulo 11: Cloudflare Workers — Serverless computing en el edge¶
elprofe.org está en el aire. Pero mientras construías el proyecto de este capítulo, seguramente te preguntaste: ¿y si necesito algo que Pages no puede hacer? ¿Tareas programadas? ¿Estado compartido entre solicitudes? ¿Una API que sirva a múltiples aplicaciones al mismo tiempo?
Ahí es donde entran los Cloudflare Workers: la pieza más primitiva y poderosa de todo el ecosistema de Cloudflare. Si Pages es el departamento de diseño —bonito, organizado, integrado con Git—, Workers es la sala de máquinas: cruda, flexible, sin restricciones.
En el Capítulo 11 construiremos nlink.uk, un acortador de URLs de alta disponibilidad que puede manejar millones de redirecciones al día desde el edge. Aprenderemos:
- El modelo de ejecución de Workers: Isolates de V8, no contenedores ni máquinas virtuales. Por qué esto lo hace el entorno serverless más rápido del mercado.
- KV, D1, R2 y Durable Objects: El arsenal de almacenamiento de Cloudflare y cuándo usar cada herramienta.
- Wrangler CLI: El flujo de trabajo profesional para desarrollar, probar localmente y desplegar Workers.
- Cron Triggers: Cómo ejecutar código en el edge de forma programada (para limpiar URLs expiradas en
nlink.uk). - Workers for Platforms: La versión multitenant de Workers, para cuando tu producto es la infraestructura.
La línea que separa Pages de Workers es cada vez más delgada. Para el momento en que termines el Capítulo 11, tendrás el mapa completo de cuándo usar cada herramienta y cómo hacer que trabajen juntas.
Referencias bibliográficas¶
-
Cloudflare. (2026). Cloudflare Pages Documentation. Documentación oficial de Pages, incluyendo límites de planes, framework presets y guías de configuración. https://developers.cloudflare.com/pages/
-
Cloudflare. (2026). Pages Functions Documentation. Guía completa de Pages Functions: enrutamiento, middleware, bindings y diferencias con Workers. https://developers.cloudflare.com/pages/functions/
-
Cloudflare. (2026). Build configuration — Cloudflare Pages. Detalle del Build System v3, variables de entorno automáticas y configuración de frameworks. https://developers.cloudflare.com/pages/configuration/build-configuration/
-
Cloudflare. (2026). Redirects — Cloudflare Pages. Sintaxis completa del archivo
_redirects, wildcards, splats y límites. https://developers.cloudflare.com/pages/configuration/redirects/ -
Cloudflare. (2026). Headers — Cloudflare Pages. Sintaxis del archivo
_headersy ejemplos de uso. https://developers.cloudflare.com/pages/configuration/headers/ -
Cloudflare. (2026). Custom domains — Cloudflare Pages. Proceso de configuración de dominios personalizados y HTTPS automático. https://developers.cloudflare.com/pages/configuration/custom-domains/
-
Cloudflare. (2026). Pricing — Workers & Pages. Tabla oficial de precios y límites del plan Free y Workers Paid. https://www.cloudflare.com/plans/developer-platform/
-
Cloudflare. (2026). next-on-pages — @cloudflare/next-on-pages. Guía para desplegar Next.js en Cloudflare Pages, incluyendo funcionalidades soportadas y limitaciones. https://developers.cloudflare.com/pages/framework-guides/nextjs/
-
Cloudflare Blog. (2021, April 21). Cloudflare Pages goes full-stack. Anuncio original de Pages Functions y la transición a full-stack. https://blog.cloudflare.com/cloudflare-pages-goes-full-stack/
-
Cloudflare Blog. (2025, May). Announcing Build System v3 for Cloudflare Pages. Descripción de las actualizaciones de runtimes en el Build System v3. https://blog.cloudflare.com/pages-build-system-v3/
-
Biilmann, M., & Preston-Werner, T. (2015). A step-by-step guide: Deploying a static site or single-page app. Netlify Blog. Artículo seminal que popularizó el término JAMstack. https://www.netlify.com/blog/2015/10/28/a-step-by-step-guide-deploying-a-static-site-or-single-page-app/
-
Cloudflare. (2026). Workers KV. Documentación del almacenamiento clave-valor distribuido de Cloudflare. https://developers.cloudflare.com/kv/
-
Cloudflare. (2026). Wrangler CLI. Referencia completa de la herramienta de línea de comandos de Cloudflare para Pages y Workers. https://developers.cloudflare.com/workers/wrangler/
-
Vercel. (2026). Vercel Pricing. Comparativa oficial de planes de Vercel. https://vercel.com/pricing
-
Netlify. (2026). Netlify Pricing. Comparativa oficial de planes de Netlify. https://www.netlify.com/pricing/
Fin del Capítulo 10
Nota del autor: Los precios, límites y versiones de software mencionados en este capítulo corresponden a la documentación oficial de Cloudflare de abril-junio de 2026. Dado que Cloudflare actualiza sus plataformas con frecuencia, se recomienda verificar los valores actuales en https://developers.cloudflare.com/pages/ antes de tomar decisiones de arquitectura basadas en límites específicos.