wandres.dev
DE PAGES A WORKERS · la convergencia

La paridad de funcionalidades y la tabla de equivalencias

Recorrido frente a frente de las cuatro capacidades que definían a Pages y de su equivalente exacto en Workers: los assets estáticos y su hosting gratuito, el renderizado en servidor con acceso a bindings, los dominios personalizados y las previsualizaciones por versión. Incluye la tabla de equivalencias que traduce cada concepto de Pages al campo correspondiente de `wrangler.jsonc`, y las tres diferencias reales que quedan.

⏱ 18 min

Decir que dos productos alcanzaron la paridad es una afirmación fuerte y merece verificarse capacidad por capacidad, no creerse por anuncio. La utilidad práctica de hacerlo es doble: si vas a migrar, necesitas saber a qué campo concreto se traduce cada cosa que hoy usas; y si vas a empezar de cero, necesitas saber qué nombres buscar cuando pidas algo que en la vieja documentación se llamaba de otra forma. Esta lección hace ese recorrido de frente: las cuatro capacidades que retenían a la gente en Pages, su equivalente exacto en Workers, la tabla que traduce un vocabulario al otro, y las tres diferencias que todavía existen y conviene conocer antes de tocar nada.

🎯 Al terminar esta lección sabrás
  • Verificar las cuatro capacidades de la paridad: assets, renderizado en servidor, dominios y previsualizaciones.
  • Traducir cada concepto de Pages al campo equivalente de wrangler.jsonc.
  • Entender por qué el modelo de precios de los assets es la pieza que sostiene la paridad.
  • Reconocer las diferencias que quedan y decidir si alguna te afecta.

Las cuatro capacidades, una a una

El método para verificar una paridad es siempre el mismo: nombrar la capacidad tal como la usa quien la tiene, buscar el mecanismo que la cubre en el otro lado, y comprobar que no solo existe sino que cuesta lo mismo y se comporta igual bajo carga. Aplicado a este caso, salen cuatro capacidades y ninguna queda coja.

Assets estáticos. En Pages el hosting estático era el producto: subías un directorio de build y se servía desde el edge, gratis e ilimitado. En Workers esa misma capacidad vive en el bloque assets del manifiesto. Apuntas directory a la carpeta de salida de tu build y el edge sirve esos archivos con la misma red y la misma caché. Lo determinante es que las peticiones resueltas por un asset no cuentan como invocación del Worker: no se factura por servir tu front-end en ninguno de los dos productos.

El bloque no se limita a apuntar a una carpeta. Admite declarar cabeceras por patrón de ruta, redirecciones, el comportamiento ante rutas sin archivo y el orden de resolución frente al código. Es decir, cubre exactamente lo que en Pages se repartía entre dos archivos especiales del directorio de salida y algunas casillas del panel, pero en un solo lugar y versionado con el proyecto.

Hay un matiz sobre los assets que conviene no pasar por alto: en Workers el directorio no es solo un origen pasivo. Si declaras el campo binding, tu código obtiene un objeto capaz de pedir un asset por su cuenta, lo que permite decidir algo antes de entregarlo —comprobar una sesión, elegir entre dos variantes, añadir una cabecera— sin renunciar a que el resto del sitio se siga sirviendo solo. Pages no ofrecía ese punto intermedio: un archivo se servía o no se servía.

Renderizado en servidor. Aquí Pages era el que iba detrás. Su modelo de funciones dependía del directorio functions/, donde cada archivo se convertía en una ruta por convención de nombres, con un acceso a la plataforma que siempre fue parcial. En Workers el renderizado en servidor no es un añadido: es el producto. Tu main apunta a un módulo con un handler fetch, y ese handler tiene el objeto env completo, con todos los bindings, sin ninguna categoría de segunda clase.

La diferencia se aprecia en cuanto miras qué puede hacer ese handler sin pedir permiso a nadie. Puede consultar una base de datos, leer y escribir en almacenamiento de objetos, invocar un modelo de lenguaje, hablar con otro Worker sin salir a la red pública, coordinar estado con un objeto durable y diferir trabajo después de responder. En Pages, cada una de esas capacidades era una pregunta con respuesta incierta; en Workers todas son la misma respuesta, que es un campo más en el manifiesto.

Dominios personalizados. Pages permitía asociar un dominio a un proyecto desde el panel. Workers ofrece lo mismo y algo más fino: además de asociar un dominio propio, puedes declarar rutas que capturan solo una parte del tráfico de una zona, lo que te deja convivir con un origen existente mientras migras por partes.

Esa distinción entre asociar un dominio y declarar rutas es la que convierte una migración arriesgada en una gradual. Un dominio personalizado dice que todo el tráfico de ese nombre es tuyo; una ruta dice que solo lo es el que coincide con un patrón, y el resto sigue su camino anterior. Con rutas puedes llevarte primero una sección del sitio, observarla en producción real, y ampliar el patrón cuando la evidencia acompañe.

Previsualizaciones. Era el argumento afectivo más fuerte a favor de Pages: cada rama y cada commit con su URL. Workers cubre esa necesidad con URLs de previsualización por versión desplegada, integradas con el mismo flujo de Git. El detalle mental que cambia es el eje: en Pages la previsualización colgaba de la rama; en Workers cuelga de la versión, que es una unidad más precisa porque es exactamente lo que se despliega.

Ese cambio de eje tiene una consecuencia que va más allá de la comodidad. Cuando la unidad es la versión, subir y activar dejan de ser el mismo acto: puedes publicar algo sin que reciba tráfico, revisarlo en su URL, promoverlo después y, si hace falta, repartir el tráfico entre la versión nueva y la anterior. Pages nunca ofreció esa separación, y es probablemente la capacidad en la que Workers no alcanza la paridad sino que la supera.

flowchart LR
A[Assets estaticos] --> Z[Bloque assets en wrangler]
B[Funciones en directorio functions] --> Y[Handler fetch en main]
C[Dominios del panel] --> X[Custom domains y routes]
D[Preview por rama] --> W[Preview URL por version]
style Z fill:#a6e3a1,color:#11111b
style Y fill:#a6e3a1,color:#11111b
style X fill:#a6e3a1,color:#11111b
style W fill:#a6e3a1,color:#11111b

La tabla de equivalencias

Esta es la traducción que conviene tener a mano durante una migración. La columna de la izquierda es lo que hoy tienes; la de la derecha, dónde vive ahora. Léela en las dos direcciones: de izquierda a derecha si estás migrando, y de derecha a izquierda si estás leyendo documentación antigua y necesitas saber de qué te hablaba.

Concepto en Pages Equivalente en Workers Nota
Directorio de build publicado assets.directory Apunta a la carpeta de salida del build
Directorio functions/ main con un handler fetch El enrutado por nombre de archivo pasa a ser código
Archivo _headers assets.headers o cabeceras en código Se declara en el manifiesto o se añade en la respuesta
Archivo _redirects assets.redirects o lógica en el handler Las reglas simples se declaran; las complejas se programan
Modo aplicación de página única assets.not_found_handling Valores single-page-application | 404-page | none
Variables de entorno del panel vars y wrangler secret put Texto plano en el manifiesto, secretos aparte
Bindings del panel Bloques de bindings del manifiesto Todos disponibles, sin categorías parciales
Dominio del proyecto Dominio personalizado o routes Las rutas permiten migrar por partes
Preview por rama URL de previsualización por versión El eje pasa de la rama a la versión desplegada
Build automático en cada push Workers Builds o GitHub Actions Se trata en la lección siguiente
Sin equivalente triggers con expresiones cron Capacidad que Pages nunca tuvo
Sin equivalente Durable Objects y colas Estado coordinado y trabajo diferido
Sin equivalente Comunicación directa entre Workers Sin salir a la red pública

El patrón que atraviesa la tabla entera es que la configuración cambia de lugar: deja de vivir en un panel del navegador y pasa a vivir en un archivo del repositorio. Ese desplazamiento tiene tres efectos que se notan enseguida. La configuración se revisa como código, en el mismo sitio donde se revisa todo lo demás. Se reproduce en local, porque el entorno de desarrollo lee el mismo archivo. Y se recupera, porque su historial es el del repositorio y no la memoria de quien pinchó la última vez.

Tres observaciones sobre la tabla. La primera es que casi todo lo que era una convención implícita en Pages se convierte en una declaración explícita en Workers: no se pierde la capacidad, se pierde la magia, y a cambio la configuración deja de vivir en un panel y pasa a estar versionada junto al código. La segunda es que la fila del directorio functions/ es la única que exige escribir código en lugar de rellenar un campo, y por eso ocupa una lección entera. La tercera es la más significativa: las últimas filas no tienen columna izquierda. La paridad no fue un empate, fue una absorción, y quien migra no solo conserva lo que tenía sino que hereda una plataforma entera que antes le quedaba al otro lado del muro.

Hay una fila que merece un comentario aparte por lo mucho que se malinterpreta: la de not_found_handling. En Pages, el comportamiento ante una ruta sin archivo dependía de una convención y de si existía o no una página de error en el directorio de salida. En Workers es un campo con tres valores posibles y una consecuencia visible en cada uno: devolver el documento principal para que el enrutador del cliente se ocupe, devolver tu página de error con el código correcto, o no hacer nada y dejar que la petición caiga en tu handler. Elegir mal aquí produce el fallo más frecuente de toda migración, que es un sitio de página única donde las rutas profundas funcionan al navegar pero devuelven un error al recargar.

El manifiesto resultante hace visible esa herencia en un solo vistazo:

{
  "assets": {
    "directory": "./dist",
    "not_found_handling": "single-page-application",
    "headers": { "/assets/*": { "cache-control": "public, max-age=31536000" } }
  },
  "triggers": { "crons": ["0 3 * * *"] }
}

La paridad económica

Una tabla de funciones puede estar completa y aun así describir dos productos que no son intercambiables, porque la misma capacidad a distinto precio no es la misma capacidad. Por eso la fila que decidía la migración no aparece en la tabla anterior: es la de cuánto cuesta servir un archivo.

La prueba mental es sencilla. Imagina la paridad de 2026 con todas las funciones idénticas salvo que cada asset servido contase como una invocación. Técnicamente sería la misma tabla; en la práctica no habría migrado nadie con tráfico real, porque un sitio de contenido dispara decenas de peticiones de archivo por visita y la factura se multiplicaría por un factor que ninguna elegancia de configuración compensa. La paridad de funciones es condición necesaria; la paridad económica es la suficiente.

En Pages, el hosting estático era gratuito e ilimitado, y esa gratuidad sostenía todo el producto. En Workers, desde 2026, las peticiones que resuelve un asset tampoco cuentan como invocación. No es una promoción ni un umbral generoso: es la misma condición en ambos lados. Un sitio con un millón de visitas diarias que sirve imágenes, hojas de estilo y fragmentos de JavaScript paga por esos archivos exactamente lo mismo aquí y allí, es decir, nada.

El coste aparece solo cuando se ejecuta código, y ahí es donde tu manifiesto se convierte en una decisión de factura. Cada ruta que declaras en run_worker_first deja de ser gratuita, porque garantiza que el Worker la vea antes que los assets. Es exactamente la propiedad que quieres para tu API y exactamente la que no quieres para tu directorio de imágenes. La arquitectura y el precio dejan de ser dos conversaciones separadas.

De ahí sale una heurística útil para diseñar: mira tu sitio y pregúntate qué fracción de las peticiones necesita de verdad que se ejecute código. En un sitio de contenido, esa fracción suele estar por debajo del cinco por ciento, y el modelo te cobra exactamente por ese cinco por ciento. En una aplicación con sesión en cada vista, la fracción se acerca al total, y entonces el precio refleja lo que realmente estás haciendo, que es computar. El modelo no premia ni castiga arquitecturas: hace visible cuál tienes.

Esa correspondencia entre manifiesto y factura es, de hecho, una herramienta de revisión. Un cambio en la lista de run_worker_first es un cambio de coste, y merece leerse en una revisión de código con la misma atención que un cambio de consulta a la base de datos.

Queda un detalle administrativo que elimina la última fricción: Pages y Workers comparten el mismo plan de pago. Migrar no implica contratar nada nuevo, ni duplicar una suscripción durante la transición, ni justificar una línea de gasto adicional ante nadie. Puedes tener los dos productos vivos a la vez mientras compruebas que el nuevo responde igual que el viejo, sin coste añadido por el solapamiento, que es justamente lo que hace segura la migración gradual.

Lo que todavía difiere

La paridad es real, pero no significa identidad, y el ingeniero honesto conoce las costuras que quedan. Ninguna de las tres siguientes es una capacidad perdida; las tres son cambios de reparto de responsabilidad, y por eso se notan sobre todo en las primeras horas de trabajo con un proyecto migrado.

🧭

El enrutado deja de ser mágico

En Pages, la estructura de carpetas de functions/ definía las rutas. En Workers hay un único punto de entrada y el enrutado lo escribes tú o lo delega un router. Es más explícito y también más trabajo inicial.

🔀

El orden de resolución es tuyo

Con assets y main juntos, cada petición intenta primero el asset y solo cae en el código si no hay archivo. Puedes invertirlo por rutas con run_worker_first, pero ahora esa decisión es explícita y tiene consecuencias de coste.

🧱

El manifiesto sustituye al panel

Lo que en Pages se configuraba pinchando en la interfaz vive ahora en un archivo versionado. Es una mejora para la reproducibilidad y un cambio de hábito para quien administraba desde el navegador.

Las tres diferencias tienen una raíz común y merece la pena nombrarla: Pages optimizaba para que no tuvieras que decidir, y Workers optimiza para que puedas decidir. Donde antes había una convención que resolvía el caso frecuente y no admitía excepciones, ahora hay un campo que rellenas. Eso convierte los primeros minutos en algo más laborioso y los meses siguientes en algo más manejable, porque cada comportamiento del sistema tiene un lugar donde está escrito. Ninguna de las tres es una capacidad perdida; las tres son responsabilidad recuperada.

💡
Verifica la paridad contra tu proyecto, no contra la lista

La tabla de arriba es exhaustiva para el proyecto medio, pero tu proyecto no es el medio. Antes de migrar, haz el ejercicio inverso: recorre tu configuración actual línea por línea, incluidos los archivos _headers y _redirects, las variables del panel y cualquier función del directorio functions/, y anota al lado de cada elemento su destino. Lo que no encuentre destino es exactamente tu riesgo de migración, y suele ser una lista muy corta. Hacer ese inventario antes de tocar nada convierte una migración incierta en una lista de tareas cerrada.

La paridad se demuestra en la economía, no en la lista de funciones

Hay una manera ingenua de leer una convergencia de productos y una manera adulta. La ingenua consiste en cotejar dos listas de funciones y declarar la paridad cuando ninguna casilla queda vacía; es la lectura del comparador de precios, y falla sistemáticamente porque una capacidad que existe pero cuesta veinte veces más no es la misma capacidad. La adulta consiste en preguntar por el modelo económico, porque el precio de una operación no es un detalle comercial pegado encima del sistema: es la expresión más honesta de qué le cuesta de verdad al proveedor, y por tanto de qué arquitectura está dispuesto a sostener a largo plazo. En esta convergencia concreta, la casilla que decidía todo no era el renderizado en servidor ni los dominios, que son problemas de ingeniería resueltos hace años; era si servir un archivo estático desde el edge iba a contar como una invocación de cómputo. Mientras contase, ningún equipo con tráfico serio habría movido un solo sitio, por elegante que fuese el manifiesto, y la paridad habría sido una nota de prensa. Al dejar de contar, la aritmética de mover un proyecto entero pasa a ser neutra, y solo entonces la lista de funciones empieza a significar algo. La consecuencia práctica va mucho más allá de este caso: cuando evalúes cualquier plataforma, aprende a leer la tabla de precios como si fuera documentación de arquitectura, porque lo es. Te dice qué operaciones el proveedor considera baratas y quiere que multipliques, cuáles considera caras y quiere que raciones, y dónde está dispuesto a subvencionar para ganar la migración. Un modelo que cobra por invocación te empuja a agrupar trabajo; uno que cobra por tiempo de CPU te empuja a no bloquear; uno que regala el tráfico estático te está diciendo, sin decirlo, que quiere ser el sitio donde vive tu front-end entero. Leer esa señal a tiempo es la diferencia entre elegir una plataforma por su folleto y elegirla por la forma que tendrá tu sistema dentro de tres años.

⚔️ Traduce tu configuración entera
  1. Toma un proyecto de Pages, tuyo o de ejemplo, y haz el inventario completo de su configuración: build, variables, archivos _headers y _redirects, funciones y dominios.
  2. Rellena la tabla de equivalencias con tu caso concreto y marca en rojo cualquier elemento que no encuentre destino claro.
  3. Escribe el bloque assets que reproduce tu comportamiento actual de rutas no encontradas y justifica el valor elegido para not_found_handling.
  4. Explica con tus palabras por qué el eje de las previsualizaciones pasa de la rama a la versión, y qué gana el equipo con ese cambio.
  5. Argumenta por qué la gratuidad de los assets es la condición que sostiene toda la tabla, y qué habría pasado con la migración si no existiera.