El deploy en Cloudflare Pages falla

Logs de build, variables de entorno y causas frecuentes cuando el sitio no se publica.

Síntoma y contexto

Cloudflare Pages publica sitios estáticos y aplicaciones con build conectadas a un repositorio Git. Cuando algo falla, el síntoma suele ser claro en el panel: un deploy en rojo con estado Failed, un build que tarda y termina con error, o un deploy en verde cuya web no muestra lo esperado. A veces el push a la rama principal no dispara ningún despliegue, o solo fallan las Preview deployments de las pull requests.

Esta guía se centra en fallos de build y de configuración del proyecto, no en errores de runtime del navegador después de publicar. Si el build termina bien pero la URL devuelve 404 en rutas internas, el problema puede ser de directorio de salida o de reglas de SPA, y también lo cubrimos aquí porque suele confundirse con un "deploy fallido".

Pages ejecuta tu comando de build en un entorno Linux limpio cada vez. Lo que funciona en tu portátil puede fallar allí si falta una variable de entorno, si el lockfile no está commiteado, si la versión de Node es distinta o si el comando asume archivos que están en .gitignore. El log de build es la pieza central del diagnóstico: guarda siempre las últimas treinta o cincuenta líneas antes de cambiar nada.

Causas probables

  1. Comando de build incorrecto o vacío. Si el proyecto es Eleventy, Astro, Next estático, Hugo o Vite, cada uno espera un comando distinto (npx @11ty/eleventy, npm run build, etc.). Un comando que funciona en local pero no está declarado en el panel de Pages provoca fallo inmediato o carpeta de salida vacía.
  2. Directorio de salida mal indicado. Pages necesita saber dónde quedan los archivos estáticos tras el build: public, dist, _site, out, según el framework. Si apuntas a una ruta que el build no genera, el deploy "funciona" pero publica una web vacía o antigua.
  3. Versión de Node u otra variable de entorno ausente. Proyectos con dependencias modernas pueden requerir Node 18 o 20. Sin la variable NODE_VERSION en el panel, Pages puede usar una versión por defecto incompatible con tu package.json o con el campo engines.
  4. Dependencias no instaladas o lockfile desincronizado. Si commiteas package.json pero no el lockfile, o si el lock está desactualizado respecto a las versiones pedidas, npm ci falla en el entorno de build. Lo mismo aplica a yarn o pnpm si no configuras el gestor correcto.
  5. Variables de entorno necesarias en tiempo de build. Sitios que leen API keys, URLs de CMS o flags en build (Eleventy con datos remotos, Astro con integraciones) fallan si esas variables solo existen en tu .env local y no en Pages → Settings → Environment variables.
  6. Rutas o imports que asumen archivos locales ignorados. Si el build espera imágenes, JSON o tokens en rutas no versionadas, el CI de Pages no los encuentra. Revisa qué archivos están en .gitignore y si el build los necesita.
  7. Submódulos Git o monorepo mal configurado. Repos con submódulos sin inicializar, o proyectos en subcarpeta sin "Root directory" configurado en Pages, generan errores de clone o de comando no encontrado.
  8. Límites de tiempo o tamaño del build. Builds muy pesados o bucles infinitos en generación de páginas pueden exceder el tiempo permitido. Menos común en sitios pequeños, pero aparece en generación masiva de contenido o optimización de imágenes sin límite.

Checklist copiable

DIAGNÓSTICO CLOUDFLARE PAGES - [nombre del proyecto]
Fecha: ___________  Rama: ___________

1. ESTADO DEL DEPLOY
   [ ] Failed (build)   [ ] Success pero web incorrecta
   [ ] No se dispara deploy al push
   Enlace o ID del deploy: ___________

2. REPOSITORIO
   Proveedor Git: ___________
   Rama de producción: ___________
   Root directory (si aplica): ___________

3. CONFIGURACIÓN DE BUILD EN PAGES
   Comando de build: ___________
   Directorio de salida: ___________
   NODE_VERSION (u otras): ___________

4. FRAMEWORK Y STACK
   Framework: ___________
   Gestor: npm / yarn / pnpm
   Comando que funciona en local: ___________

5. ÚLTIMAS LÍNEAS DEL LOG (pegar aquí)
   ___________
   ___________
   ___________

6. CAMBIOS RECIENTES
   [ ] package.json o lockfile
   [ ] Variables de entorno
   [ ] Migración de hosting
   [ ] Ninguno

7. NO ENVIAR
   [ ] API keys ni tokens en el mensaje
   [ ] Archivos .env completos

Qué capturar antes de escribir

Lo más valioso es el enlace al deploy fallido o su identificador, la rama implicada y las últimas líneas del log de build copiadas literalmente. Incluye el framework (Eleventy, Astro, Next, Hugo, SvelteKit estático, etc.) y el comando de build configurado en el panel de Pages, junto con el directorio de publicación.

Si el build pasa pero el sitio se ve mal, indica la URL publicada y qué esperabas ver. Una captura del panel de configuración de build (sin secretos) y del archivo relevante del repo (package.json, eleventy.config.mjs, astro.config.mjs) acorta el diagnóstico. Menciona si el mismo commit construye bien en tu máquina con el mismo comando.

No pegues en el formulario variables de entorno con valores reales, tokens de Cloudflare ni claves de API. Si el log muestra una variable, censa el valor y deja solo el nombre de la variable que falta o está mal.

Comandos y paneles útiles

Panel de Cloudflare Pages

  • Workers & Pages → tu proyecto → Deployments: Historial de builds. Entra en el deploy fallido y desplázate al final del log.
  • Settings → Builds & deployments: Comando de build, directorio de salida, rama de producción, Root directory.
  • Settings → Environment variables: Variables para Production y Preview por separado. Recuerda que cambiar una variable requiere un nuevo deploy para aplicarse al build.
  • Custom domains: Solo relevante si el build OK pero el dominio no sirve la versión nueva (caché, DNS o dominio no vinculado).

Reproducir en local

# Instalar dependencias como en CI (con lockfile)
npm ci

# Mismo comando que en Pages
npm run build

# Comprobar que existe la carpeta de salida
ls -la public/
# o dist/, _site/, out/ según tu proyecto

Configuraciones de referencia por framework:

  • Eleventy: Build command npm run build o npx @11ty/eleventy. Output public o _site según dir.output en la config.
  • Astro: Build npm run build. Output dist.
  • Next.js (static export): Requiere output: 'export' en config. Output out.
  • Hugo: Build hugo o versión fijada. Output public por defecto.
  • Vite / Vue / React SPA: Output dist. Puede hacer falta archivo public/_redirects o _routes.json para SPA fallback.

Variables de entorno frecuentes

NODE_VERSION=20
NPM_VERSION=10
# Ejemplos de nombre (valores en el panel, no en el repo):
# CMS_TOKEN
# API_URL

Pasos de diagnóstico por escenario

El log dice "Command failed with exit code 1" sin más detalle

Sube en el log hasta encontrar la primera línea en rojo con contexto: error de compilación, módulo no encontrado, syntax error, o fallo de npm ci. Los mensajes anteriores suelen ser avisos que no detienen el build. Copia desde la primera línea que mencione Error: hasta el final.

Module not found o Cannot find package

Comprueba que la dependencia está en dependencies o devDependencies del package.json commiteado, no solo instalada en local. Verifica que el archivo de lock está en el repo y actualizado. Si usas alias de importación, confirma que la config del bundler está commiteada y es compatible con el entorno Linux de Pages.

Build OK pero 404 en rutas que no son la raíz

Es un problema de enrutado, no de compilación. Para SPA, añade un fallback que sirva index.html en rutas desconocidas. En Cloudflare Pages puedes usar public/_redirects con /* /index.html 200 para SPAs, o _routes.json para control fino. En sitios estáticos con Eleventy o Hugo, cada ruta debe generarse como HTML en build; un 404 en /blog/post/ indica que el contenido no se generó o el enlace es incorrecto.

El deploy no se dispara al hacer push

Revisa que la integración Git sigue autorizada en Cloudflare y que empujas a la rama configurada como producción. Comprueba que el archivo de configuración de Pages (wrangler.toml en proyectos vinculados a Workers) no entra en conflicto. Mira si el build se saltó por "no changes detected" cuando solo cambiaste variables de entorno: en ese caso lanza un Retry deployment manual.

Errores concretos y qué suelen significar

  • npm ERR! code EUSAGE o fallo en npm ci: Lockfile ausente o no coincide con package.json. Regenera el lock en local y commitea.
  • The engine "node" is incompatible: Sube NODE_VERSION en variables de entorno o ajusta el campo engines del package.
  • ENOMEM o JavaScript heap out of memory: Build demasiado pesado. Reduce generación en build, divide el sitio o optimiza el proceso.
  • hugo: command not found: Hugo no está en el entorno por defecto. Usa la imagen de build adecuada, script de instalación, o migra el comando a npm script que instale dependencias.
  • Timeout durante build: Revisa bucles en datos, descargas remotas en build sin límite, o optimización de miles de imágenes en un solo paso.

Cuándo escalar

Puedes resolver la mayoría de fallos de Pages siguiendo el log y esta checklist. Escala o escribe por el formulario con categoría de web o despliegue cuando:

  • El log apunta a un error de permisos del repositorio o submódulo y no sabes cómo reautorizar la integración sin romper otros proyectos.
  • El build requiere un paso previo no documentado (binario custom, acceso a red privada, VPN) que el entorno de Pages no ofrece.
  • Migras desde Netlify, Vercel o GitHub Pages y el mismo repo debería construir pero falla solo en Pages tras varios intentos documentados.
  • Necesitas configurar monorepo con varios proyectos Pages desde subcarpetas y la raíz no queda clara.
  • El deploy pasa, el dominio custom está vinculado, pero los visitantes siguen viendo una versión antigua y sospechas de caché o de DNS dual.
  • Quieres revisión del comando de build y la estructura del repo antes de tocar producción en un sitio con tráfico activo.

Adjunta siempre el log final, el framework y qué probaste en local. Así el primer respuesta puede ir directo a la línea que falla, sin repetir los pasos básicos del panel de Cloudflare.

¿Sigues atascado después de la checklist?

Escribir el problema Volver al triage