Cómo migrar de Vercel a Cloudflare Workers y Railway redujo nuestros costos de infraestructura web en un 80 %

Migramos nuestra infraestructura web de Vercel a Cloudflare Workers y Railway, y sustituimos Next.js por una combinación de TanStack Router, TanStack Start y Hono según las necesidades reales de cada carga de trabajo. El resultado fue una reducción de aproximadamente el 80 % en los costes de infraestructura, que llegó a alrededor del 90 % tras filtrar el tráfico automatizado malicioso en el borde de la red. La mayor parte del trabajo de migración la realizaron agentes de IA especializados en programación, mientras que los ingenieros se centraron en la arquitectura, las restricciones, la revisión y la verificación en producción.

23 de septiembre de 2026

Quang Lam · Founder & CEO

Cómo migrar de Vercel a Cloudflare Workers y Railway redujo nuestros costos de infraestructura web en un 80 %

Durante años, Vercel fue la plataforma predeterminada en la que desplegábamos casi todo lo relacionado con la web en WebCatalog. La mayoría de esos proyectos usaban Next.js, así que la combinación era natural. Nuestros sitios de marketing, interfaces de producto, configuración de cuentas, consola para desarrolladores, autenticación, herramientas de administración y API acabaron usando prácticamente la misma pila tecnológica.

Durante mucho tiempo funcionó bien. Vercel simplificaba los despliegues, Next.js nos ofrecía un framework de pila completa productivo y rara vez teníamos que pensar en la infraestructura subyacente.

Con el tiempo, esa comodidad dejó de ajustarse a las necesidades de nuestros productos.

Nuestros sitios de marketing seguían beneficiándose del SSR (renderizado del lado del servidor), pero la mayoría de nuestras otras aplicaciones web no lo necesitaban. Podían ser simples SPA (aplicaciones de una sola página). Nuestras API necesitaban un entorno Node.js convencional, con dependencias nativas y procesos de larga duración. Casi todo el resto de nuestra pila de frontend ya utilizaba Vite. Al mismo tiempo, los costes de infraestructura eran cada vez más difíciles de ignorar, sobre todo a medida que crecía el tráfico público y automatizado.

Al principio intentamos optimizar lo que ya teníamos. Consideramos conservar Next.js y trasladarlo a Cloudflare Workers mediante un adaptador. Probamos Astro para los sitios de marketing. Durante un breve periodo alojamos nuestras API en Cloudflare Containers.

Finalmente llegamos a una solución más sencilla: la mayoría de nuestras aplicaciones web ahora usan Vite + TanStack Router en Cloudflare Workers, nuestros sitios de marketing usan TanStack Start con SSR en Cloudflare Workers y nuestras API usan Hono + tRPC en Railway, como contenedores Node.js de larga duración.

La migración redujo nuestros costes de infraestructura web aproximadamente un 80 %. Después de reforzar también nuestras reglas de seguridad de Cloudflare y bloquear más tráfico automatizado malicioso en el extremo de la red, el ahorro total aumentó hasta alrededor del 90 %.

La mayor parte de la implementación de la migración también corrió a cargo de agentes de programación con IA, principalmente Claude Fable 5 y Claude Opus 5. Los ingenieros decidieron la arquitectura, definieron las restricciones, revisaron los cambios y verificaron el resultado.

No empezamos dejando Vercel

Nuestro primer impulso fue optimizar la configuración existente.

webcatalog.io era el punto de partida más evidente porque recibe mucho tráfico público, aunque la mayoría de sus páginas cambian con relativamente poca frecuencia. Descubrimos que una parte excesiva del sitio seguía renderizándose dinámicamente, así que corregimos el renderizado dinámico accidental, añadimos ISR (regeneración estática incremental) a las rutas de mucho tráfico, hicimos que más páginas pudieran almacenarse en caché y optimizamos el costoso procesamiento de los mapas del sitio.

El trabajo ayudó, pero también dejó más claro el problema de fondo. Dedicábamos cada vez más tiempo a entender por qué contenidos relativamente estáticos eran dinámicos, qué comportamiento del framework lo había provocado y qué mecanismo del framework debíamos introducir para que volvieran a poder almacenarse en caché.

Mientras tanto, muchas de nuestras otras aplicaciones tenían el problema contrario. La configuración de cuentas, la consola para desarrolladores, las aplicaciones de administración y la mayoría de las interfaces de producto no necesitaban renderizado del lado del servidor. Eran aplicaciones de navegador que se comunicaban con API.

En ese momento, la pregunta dejó de ser «¿Cómo reducimos nuestra factura de Vercel?» y pasó a ser «¿Qué construiríamos si estas aplicaciones no fueran ya aplicaciones Next.js?».

Consideramos ejecutar Next.js en Cloudflare

La opción menos disruptiva era conservar Next.js y trasladarlo de Vercel a Cloudflare Workers.

La consideramos seriamente porque Next.js puede ejecutarse en Cloudflare mediante capas de adaptación, lo que nos habría permitido conservar gran parte de la estructura de las aplicaciones existentes.

Pero no considerábamos que Next.js en Cloudflare fuera equivalente a Next.js en Vercel. Next.js está más estrechamente integrado con el entorno de ejecución, el sistema de despliegue, el comportamiento de la caché y las funciones de la plataforma de Vercel. En Cloudflare, un adaptador tiene que trasladar esos supuestos a un entorno de ejecución diferente.

Eso puede funcionar bien, pero, si nuestro objetivo era simplificar la pila, añadir otra capa de compatibilidad no nos parecía lo ideal.

También había una cuestión más amplia relacionada con las herramientas. Casi todo lo demás que desarrollábamos para el frontend ya usaba Vite: aplicaciones de escritorio, extensiones de navegador, SPA y otros proyectos del lado del cliente.

Next.js había apostado con fuerza por Turbopack, y Turbopack ha mejorado mucho. No era una queja sobre el rendimiento. Para nosotros, la diferencia más importante era el ecosistema. Vite ya era la base común de la mayor parte de nuestro código de frontend, con un ecosistema de plugins más amplio y configuraciones más reutilizables entre proyectos.

Por tanto, conservar Next.js en Cloudflare habría resuelto parte del problema de alojamiento, pero habría mantenido tanto la disparidad de frameworks como un ecosistema separado de herramientas de compilación.

Así que dimos un paso atrás y examinamos qué necesitaba realmente cada tipo de carga de trabajo.

Dividimos la pila según la carga de trabajo

Una vez que dejamos de buscar un único sustituto universal para Next.js, la arquitectura se volvió mucho más sencilla.

Nuestros sitios de marketing necesitaban SSR porque tienen páginas públicas y localizadas, metadatos, URL canónicas, mapas del sitio y tráfico procedente de buscadores.

La mayoría de nuestras otras aplicaciones web no necesitaban SSR y podían ser simplemente aplicaciones Vite con TanStack Router.

Nuestras API no necesitaban ningún framework de React y encajaban mejor en un entorno de ejecución Node.js convencional.

La división final quedó así:

Aplicaciones web
Vite + TanStack Router
        │
        └── Cloudflare Workers

Sitios de marketing
TanStack Start + SSR
        │
        └── Cloudflare Workers

API
Hono + tRPC
        │
        └── Railway / contenedores Node.js

La regla pasó a ser sencilla: usar SSR donde aporta un valor real, usar una SPA sencilla donde no lo aporta y ejecutar los servicios de backend en un entorno de ejecución apropiado para el backend.

La mayoría de las aplicaciones web pasaron a ser SPA

Las migraciones a SPA fueron la parte más fácil.

La aplicación web de WebCatalog se trasladó especialmente rápido: preparamos la estructura inicial de su sustituta con Vite + TanStack Router, trasladamos la interfaz, cambiamos el despliegue a Cloudflare Workers y eliminamos la antigua versión de Next.js en una misma mañana.

Repetimos el mismo patrón con la aplicación web de Lexibird, la configuración de cuentas, nuestra consola para desarrolladores, la autenticación y las aplicaciones de administración. Desde que preparamos la estructura inicial de la primera SPA hasta que eliminamos la última aplicación Next.js pasaron unos 19 días.

Para estas aplicaciones, Cloudflare Workers es deliberadamente poco complejo. Vite genera los recursos estáticos, Cloudflare los sirve y las rutas de la aplicación recurren a index.html como alternativa. No hay un entorno de ejecución SSR porque nada necesita renderizado del lado del servidor.

Lo más difícil fue conservar el comportamiento que se había acumulado alrededor de esas aplicaciones con el tiempo. Parte de la lógica de autenticación tuvo que salir de las rutas de servidor de Next.js y pasar a la API, y las versiones antiguas de la aplicación de escritorio de WebCatalog seguían dependiendo de endpoints heredados que teníamos que mantener operativos.

Trasladar la interfaz de React fue fácil.

Conservar los contratos fue más difícil.

Probamos Astro y lo eliminamos cinco días después

Los sitios de marketing fueron más difíciles.

Nuestra primera opción fue Astro, que parecía encajar de forma natural con webcatalog.io y lexibird.com porque ambos son sitios públicos con mucho contenido, y Astro se integra bien con Cloudflare.

Empezamos a trasladar ambos sitios y, cinco días después, nos detuvimos.

No hubo un único defecto decisivo. En cambio, se fueron acumulando pequeñas incompatibilidades. Algunas rutas necesitaban acceso a la base de datos durante el prerenderizado, mientras que nuestro entorno de compilación no tenía credenciales de la base de datos de producción, deliberadamente. Las islas de React hacían menos natural compartir el estado de la aplicación. También encontramos diferencias entre las rutas prerenderizadas y las renderizadas en tiempo de ejecución, además de ciertas dificultades con las herramientas en nuestro repositorio.

Ninguno de esos problemas era imposible de resolver. Precisamente por eso era peligroso continuar. Podríamos haber pasado fácilmente varias semanas más arreglando una cosa tras otra.

En lugar de eso, eliminamos la implementación y volvimos a empezar.

Los agentes de IA cambiaron el cálculo económico de esa decisión. Gran parte del trabajo mecánico de migración no había consumido semanas de tiempo de los ingenieros, así que el coste ya invertido era menor y resultaba más fácil reconocer que preferíamos otra arquitectura.

TanStack Start encajó mejor

Reiniciamos la migración de los sitios de marketing a partir del código original de Next.js, esta vez con TanStack Start.

Encajó de manera mucho más natural porque ya usábamos TanStack Router en las SPA. Así, el enrutamiento, los loaders, los parámetros de búsqueda y la navegación seguían conceptos similares. El código seguía siendo React y TypeScript convencionales, y el sistema de compilación era Vite.

Migramos lexibird.com a TanStack Start en un día. Después vino webcatalog.io.

La ventaja no era que TanStack Start resolviera mágicamente todos los problemas. Era que encajaba con la dirección que ya estaba tomando el resto de nuestra pila.

En un monorrepositorio, eso importa. Compartir herramientas de compilación permite reutilizar más plugins y configuraciones, reduce los casos especiales al depurar, exige menos cambios de contexto a los desarrolladores y deja menos convenciones específicas de cada proyecto que los agentes de programación deban descubrir.

Cloudflare resultó mucho más barato para nuestro tráfico

La arquitectura fue solo una parte de la razón por la que bajó nuestra factura. Los precios de Cloudflare fueron un factor importante, especialmente en lo relativo al ancho de banda.

Actualmente, el plan de pago de Cloudflare Workers cobra principalmente por solicitudes y uso de CPU, y no añade cargos por transferencia de datos ni ancho de banda para Workers. (developers.cloudflare.com) Esto importa mucho para los sitios web públicos, porque una solicitud puede consumir muy poca CPU y, aun así, transferir HTML, JavaScript, imágenes, fuentes y otros recursos.

El modelo de precios de Vercel también incluye categorías de uso y límites relacionados con la red, entre ellos Fast Data Transfer y Fast Origin Transfer. (vercel.com) Para nuestro perfil de tráfico, los costes de Cloudflare eran considerablemente más favorables.

El ahorro no se debió únicamente al cambio de proveedor. También trasladamos muchas aplicaciones a compilaciones estáticas de Vite, redujimos el SSR innecesario, hicimos más explícito el almacenamiento en caché y llevamos las cargas de trabajo de las API a un entorno de ejecución que se ajustaba mejor a ellas. Pero los precios de Cloudflare, especialmente en lo relativo al ancho de banda, contribuyeron de forma importante a la reducción de aproximadamente el 80 % que observamos.

Esa cifra corresponde a nuestra carga de trabajo. No significa que todas las aplicaciones que se trasladen de Vercel a Cloudflare vayan a ahorrar un 80 %.

Las API acabaron en Railway

Las API planteaban un problema aparte.

Aunque eran proyectos Next.js, en gran medida ya eran independientes de Next.js. La API de WebCatalog tenía unas 34 000 líneas, pero solo siete archivos importaban next/server. tRPC ya utilizaba su adaptador Fetch, e Inngest era compatible con Hono.

Sustituimos la capa HTTP de Next.js por Hono. Esa parte resultó sorprendentemente pequeña.

La pregunta más difícil era dónde ejecutarla. Workers sin más no encajaban bien porque las API utilizan Node.js y dependencias nativas como sharp.

Al principio probamos Cloudflare Containers, lo que nos permitió salir rápidamente de Vercel. Pero, después de ejecutar esa configuración en producción, comprobamos que su modelo operativo exigía más ajustes manuales de capacidad de los que queríamos hacer en ese momento.

Así que volvimos a trasladar las API.

Hoy se ejecutan en Railway como servicios convencionales de contenedores Node.js de larga duración. La CI (integración continua) crea las imágenes Docker, las sube a nuestro registro y Railway se encarga del escalado horizontal automático.

No todo necesita ejecutarse en el extremo de la red.

Dejar Vercel significó asumir más responsabilidades

El menor coste vino acompañado de una contrapartida.

Vercel y Next.js se habían encargado de muchos aspectos de la infraestructura a un nivel más alto. Con TanStack Start y Workers, optamos por un almacenamiento en caché HTTP explícito. Se renderiza una página, devolvemos cabeceras de caché y Cloudflare almacena la respuesta. La caché del navegador y la del extremo de la red pueden seguir políticas distintas, incluida la posibilidad de servir contenido obsoleto mientras se revalida en el extremo de la red.

Nos gustaba que esas decisiones fueran explícitas, pero una infraestructura explícita también significa que los errores son responsabilidad tuya.

Cometimos algunos. Una regla de caché en producción coincidió accidentalmente con respuestas de funciones de servidor de TanStack específicas de cada visitante, y otra configuración de caché interactuó mal con el comportamiento de la ruta alternativa de las SPA. Esos fallos nos recordaron que no se puede demostrar la corrección de una migración examinando únicamente el repositorio. La infraestructura de producción también forma parte del sistema.

Los agentes de IA cambiaron nuestra forma de migrar

La mayor parte de la implementación la realizaron agentes de programación, principalmente Claude Fable 5 y Claude Opus 5.

Las migraciones de frameworks se prestan especialmente bien al trabajo con agentes porque buena parte de la tarea cuenta con una referencia existente clara. Trasladar esta ruta, conservar esta URL, sustituir esta API del framework, mantener los mismos metadatos, ejecutar la comprobación de tipos, corregir los errores y comparar el resultado con la implementación anterior.

Para webcatalog.io, mantuvimos un registro de la migración que dividía el trabajo en etapas como la base, las páginas de producto, las páginas de catálogo, la búsqueda, el blog, los precios, las redirecciones, los mapas del sitio y la transición final. En vez de pedirle a un agente «migra webcatalog.io a TanStack Start», le asignamos tareas acotadas con requisitos invariables explícitos.

La aplicación existente se convirtió en la especificación. El trabajo del agente era reproducir el comportamiento con la nueva arquitectura, no reinventar el producto.

Eso desplazó el esfuerzo humano de traducir código manualmente a plantear preguntas como estas: ¿Debería esta página usar SSR? ¿Qué comportamiento es intencionado? ¿Qué puede almacenarse en una caché global? ¿Qué URL deben seguir siendo idénticas? ¿Dónde debe producirse la autenticación? ¿Cuándo debemos dejar de intentar que funcione un enfoque?

Seguimos revisando los resultados, ejecutando compilaciones y comprobaciones de tipos, y verificando manualmente áreas de mayor riesgo como la autenticación, el SEO (optimización para motores de búsqueda), las redirecciones y la caché.

El cambio importante no fue que la IA escribiera código por nosotros. Fue que la IA abarató la experimentación.

Resultó mucho más fácil justificar probar Astro y eliminarlo cinco días después. Trasladar las API una vez y luego decidir que otra plataforma encajaba mejor fue menos doloroso. El trabajo mecánico costaba menos, así que podíamos cambiar de rumbo cuando la arquitectura era incorrecta, en lugar de seguir adelante solo porque ya habíamos invertido demasiado en ella.

Los agentes hicieron que la implementación fuera un recurso menos escaso.

Eso dio más importancia a la arquitectura, las restricciones, la revisión y la verificación.

El 80 % pasó a ser aproximadamente un 90 %

Después de la migración, nuestros costes de infraestructura web eran aproximadamente un 80 % menores.

Entonces empezamos a prestar más atención a qué solicitudes llegaban siquiera a las aplicaciones.

Una proporción considerable del tráfico público de internet es automatizado: motores de búsqueda, rastreadores de IA, agentes, herramientas de extracción de datos, escáneres y bots menos amistosos. Parte de ese tráfico es útil y parte no.

Con las aplicaciones directamente detrás de Cloudflare, reforzamos nuestras reglas de seguridad para rechazar el tráfico automatizado malicioso en el extremo de la red, antes de que activara procesos en las aplicaciones o consultas a la base de datos.

Después de eso, nuestro ahorro total alcanzó aproximadamente el 90 % en comparación con la configuración anterior.

La reducción final fue el resultado de varios factores combinados: los precios más bajos de Cloudflare, especialmente en ancho de banda; menos trabajo del lado del servidor; un entorno de ejecución más adecuado para nuestras API; un almacenamiento en caché más explícito; y menos solicitudes innecesarias que llegaban a las aplicaciones.

Nuestra arquitectura actual

Ya no queda ninguna aplicación Next.js en nuestro repositorio. La mayoría de nuestras aplicaciones web son ahora SPA de Vite + TanStack Router en Cloudflare Workers. webcatalog.io y lexibird.com usan TanStack Start en Cloudflare Workers porque esos sitios sí se benefician realmente del SSR. Nuestras API usan Hono + tRPC en Railway y se ejecutan como contenedores Node.js convencionales. Casi todos nuestros proyectos de frontend forman ahora parte del ecosistema de Vite.

Nuestros costes de infraestructura bajaron aproximadamente un 80 %, gracias en gran medida a que los precios de Cloudflare se ajustaban mucho mejor a nuestro tráfico, especialmente en lo relativo al ancho de banda. Filtrar el tráfico automatizado malicioso en el extremo de la red elevó el ahorro global a alrededor del 90 %.

Pero el resultado que más nos importa es el arquitectónico. Los sitios de marketing cuentan con SSR, todo lo demás que puede ser una SPA es una SPA y las API se ejecutan en servidores convencionales cuando esa es la opción más sencilla.

Empezamos intentando abaratar Vercel.

Terminamos dándonos cuenta de que no necesitábamos gran parte de la arquitectura por la que estábamos pagando.