Как переход с Vercel на Cloudflare Workers и Railway сократил наши расходы на веб-инфраструктуру на 80 %

Мы перенесли наш веб-стек с Vercel на Cloudflare Workers и Railway, заменив Next.js сочетанием TanStack Router, TanStack Start и Hono в зависимости от потребностей каждой рабочей нагрузки. В результате расходы на инфраструктуру сократились примерно на 80%, а после фильтрации вредоносного автоматизированного трафика на периферии сети — примерно на 90%. Большую часть работы по миграции выполнили ИИ-агенты для написания кода, а инженеры сосредоточились на архитектуре, ограничениях, проверке изменений и верификации работы в продакшене.

23 сентября 2026 г.

Quang Lam · Founder & CEO

Как переход с Vercel на Cloudflare Workers и Railway сократил наши расходы на веб-инфраструктуру на 80 %

На протяжении многих лет в WebCatalog мы по умолчанию развёртывали почти всё, что работало в интернете, на Vercel. Большинство этих проектов использовали Next.js, поэтому сочетание было естественным. Маркетинговые сайты, интерфейсы продуктов, настройки учётных записей, консоль разработчика, аутентификация, инструменты администрирования и API — всё в итоге работало примерно на одном стеке.

Долгое время это нас устраивало. Vercel упрощал развёртывание, Next.js давал удобный полнофункциональный фреймворк, а нам редко приходилось задумываться об инфраструктуре под ними.

Но со временем это удобство перестало соответствовать потребностям наших продуктов.

Нашим маркетинговым сайтам по-прежнему был полезен SSR (серверный рендеринг), но большинству остальных веб-приложений он не требовался. Они могли быть обычными SPA (одностраничными приложениями). Нашим API нужна была стандартная среда Node.js с нативными зависимостями и долгоживущими процессами. Почти весь остальной фронтенд-стек уже использовал Vite. При этом расходы на инфраструктуру становилось всё труднее игнорировать, особенно по мере роста публичного и автоматизированного трафика.

Сначала мы попытались оптимизировать то, что уже было. Мы рассматривали возможность оставить Next.js и перенести его на Cloudflare Workers через адаптер. Попробовали Astro для маркетинговых сайтов. Ненадолго разместили API в Cloudflare Containers.

В итоге мы пришли к более простому решению: большинство наших веб-приложений теперь используют Vite + TanStack Router на Cloudflare Workers, маркетинговые сайты — TanStack Start с SSR на Cloudflare Workers, а API — Hono + tRPC на Railway в виде долгоживущих контейнеров Node.js.

Миграция сократила расходы на веб-инфраструктуру примерно на 80%. После того как мы также ужесточили правила безопасности Cloudflare и стали блокировать больше враждебного автоматизированного трафика на периферии сети, общая экономия выросла примерно до 90%.

Большую часть работы по миграции также выполнили ИИ-агенты для написания кода, в основном Claude Fable 5 и Claude Opus 5. Инженеры при этом принимали архитектурные решения, определяли ограничения, проверяли изменения и подтверждали результат.

Мы не начинали с ухода с Vercel

Первым порывом было оптимизировать существующую конфигурацию.

Очевидной отправной точкой стал webcatalog.io: он получает много публичного трафика, хотя большинство его страниц меняются сравнительно редко. Мы обнаружили, что слишком большая часть сайта по-прежнему рендерится динамически. Поэтому мы устранили случаи непреднамеренного динамического рендеринга, добавили ISR (инкрементальную статическую регенерацию) для маршрутов с высоким трафиком, сделали больше страниц пригодными для кеширования и оптимизировали затратную обработку карт сайта.

Это помогло, но одновременно яснее показало основную проблему. Мы тратили всё больше времени на выяснение того, почему относительно статичный контент оказался динамическим, какое поведение фреймворка к этому привело и какой механизм фреймворка нужно задействовать, чтобы снова сделать его кешируемым.

У многих других наших приложений проблема была противоположной. Настройки учётных записей, консоль разработчика, административные приложения и большинство интерфейсов продуктов вообще не нуждались в серверном рендеринге. Это были браузерные приложения, взаимодействующие с API.

В какой-то момент вопрос перестал звучать как «Как уменьшить счёт за Vercel?» и стал звучать так: «Что бы мы построили, если бы эти приложения ещё не были приложениями на Next.js?»

Мы рассматривали Next.js на Cloudflare

Наименее болезненным вариантом было сохранить Next.js и перенести его с Vercel на Cloudflare Workers.

Мы всерьёз рассматривали этот вариант: Next.js может работать на Cloudflare через адаптеры, а значит, мы смогли бы сохранить большую часть существующей структуры приложений.

Но мы не считали Next.js на Cloudflare эквивалентом Next.js на Vercel. Next.js теснее всего интегрирован со средой выполнения Vercel, её системой развёртывания, механизмами кеширования и возможностями платформы. На Cloudflare адаптеру приходится переносить эти предположения на другую среду выполнения.

Такой подход может хорошо работать, но, если цель — упростить стек, добавление ещё одного слоя совместимости не казалось идеальным решением.

Был и более общий вопрос инструментов. Почти всё остальное, что мы разрабатывали для фронтенда, уже использовало Vite: десктопные приложения, расширения браузера, SPA и другие клиентские проекты.

Next.js в значительной степени перешёл на Turbopack, и Turbopack заметно улучшился. Дело было не в претензиях к производительности. Для нас важнее была экосистема. Vite уже служил общей основой для большей части нашего фронтенд-кода: у него более широкая экосистема плагинов, а конфигурации легче повторно использовать в разных проектах.

Таким образом, сохранение Next.js на Cloudflare решило бы часть проблемы с хостингом, но оставило бы и расхождение между фреймворками, и отдельную экосистему инструментов сборки.

Поэтому мы сделали шаг назад и посмотрели, что на самом деле нужно каждой рабочей нагрузке.

Мы разделили стек по типам задач

Когда мы перестали искать одну универсальную замену Next.js, архитектура стала гораздо проще.

Маркетинговым сайтам требовался SSR: у них есть публичные локализованные страницы, метаданные, канонические URL, карты сайта и трафик из поисковых систем.

Большинству остальных веб-приложений SSR был не нужен: они могли быть просто приложениями на Vite с TanStack Router.

Нашим API вообще не требовался React-фреймворк — для них лучше подходила стандартная среда выполнения Node.js.

Итоговое разделение выглядело так:

Веб-приложения
Vite + TanStack Router
        │
        └── Cloudflare Workers

Маркетинговые сайты
TanStack Start + SSR
        │
        └── Cloudflare Workers

API
Hono + tRPC
        │
        └── Railway / контейнеры Node.js

Правило стало простым: использовать SSR там, где он приносит реальную пользу, обычный SPA — там, где не приносит, а серверные сервисы запускать в серверной среде выполнения.

Большинство веб-приложений стали SPA

Перенести приложения на SPA было проще всего.

Особенно быстро мы перенесли веб-приложение WebCatalog: создали каркас замены на Vite + TanStack Router, перенесли интерфейс, переключили развёртывание на Cloudflare Workers и удалили старую версию на Next.js — всё за одно утро.

По той же схеме мы перенесли веб-приложение Lexibird, настройки учётных записей, консоль разработчика, аутентификацию и административные приложения. От создания каркаса первого SPA до удаления последнего приложения на Next.js прошло около 19 дней.

Для этих приложений Cloudflare Workers намеренно выполняет самую простую работу. Vite собирает статические ресурсы, Cloudflare их отдаёт, а маршруты приложения при необходимости направляются на index.html. Среды выполнения SSR нет, поскольку серверный рендеринг ничему из этого не нужен.

Сложнее было сохранить поведение, накопившееся вокруг этих приложений со временем. Часть логики аутентификации пришлось перенести из серверных маршрутов Next.js в API, а старые версии десктопного приложения WebCatalog всё ещё зависели от прежних эндпоинтов, работоспособность которых нужно было сохранить.

Перенести интерфейс на React было легко.

Сохранить существующие контракты — сложнее.

Мы попробовали Astro и удалили его через пять дней

С маркетинговыми сайтами всё оказалось сложнее.

Сначала мы выбрали Astro. Он казался естественным решением для webcatalog.io и lexibird.com: оба сайта публичные, содержат много контента, а Astro хорошо интегрируется с Cloudflare.

Мы начали переносить оба сайта, но через пять дней остановились.

Не было одного критического недостатка. Вместо этого накапливались мелкие несоответствия. Некоторым маршрутам во время предварительного рендеринга требовался доступ к базе данных, тогда как в нашей среде сборки намеренно не было учётных данных для производственной базы. Из-за React-островов было менее удобно работать с общим состоянием приложения. Мы также столкнулись с различиями между заранее подготовленными маршрутами и маршрутами, рендерящимися во время выполнения, а также с некоторыми неудобствами инструментов в нашем репозитории.

Ни одна из этих проблем не была неразрешимой. Именно поэтому продолжать было опасно: мы легко могли потратить ещё несколько недель, исправляя одно за другим.

Вместо этого мы удалили реализацию и начали заново.

ИИ-агенты изменили экономику такого решения. Значительная часть механического переноса не потребовала недель работы инженеров, поэтому уже понесённые затраты были меньше и нам было проще признать, что мы предпочитаем другую архитектуру.

TanStack Start подошёл лучше

Мы начали перенос маркетинговых сайтов заново, взяв за основу исходный код на Next.js и на этот раз выбрав TanStack Start.

Он подошёл гораздо естественнее: мы уже использовали TanStack Router в SPA, поэтому маршрутизация, загрузчики, параметры поиска и навигация строились на схожих принципах. Код оставался обычным React и TypeScript, а системой сборки был Vite.

Мы перенесли lexibird.com на TanStack Start за день. Затем последовал webcatalog.io.

Преимущество было не в том, что TanStack Start волшебным образом решал любую проблему. Он соответствовал направлению, в котором уже развивался остальной наш стек.

В монорепозитории это важно. Общие инструменты сборки позволяют повторно использовать больше плагинов и настроек, уменьшают число особых случаев при отладке и необходимость переключаться между разными инструментами для разработчиков, а ИИ-агентам приходится осваивать меньше соглашений, специфичных для отдельных проектов.

Cloudflare обходился гораздо дешевле при нашем профиле трафика

Архитектура была лишь одной из причин снижения расходов. Важную роль сыграли тарифы Cloudflare, особенно стоимость передачи данных.

Сейчас в платном тарифе Cloudflare Workers плата в основном зависит от количества запросов и использования процессорного времени; дополнительной платы за передачу данных или пропускную способность для Workers нет. (developers.cloudflare.com) Для публичных сайтов это очень важно: запрос может требовать совсем немного процессорного времени, но при этом передавать HTML, JavaScript, изображения, шрифты и другие ресурсы.

Тарифная модель Vercel также включает категории и лимиты, связанные с сетевой нагрузкой, в том числе Fast Data Transfer и Fast Origin Transfer. (vercel.com) При нашем профиле трафика экономика Cloudflare была существенно выгоднее.

Экономия возникла не только благодаря смене провайдера. Мы также перевели многие приложения на статические сборки Vite, сократили ненужный SSR, сделали кеширование более явным и перенесли API в более подходящую для них среду выполнения. Но тарифы Cloudflare, особенно в части передачи данных, внесли большой вклад в наблюдавшееся нами снижение расходов примерно на 80%.

Эта цифра относится к нашей рабочей нагрузке. Мы не утверждаем, что любое приложение при переходе с Vercel на Cloudflare сэкономит 80%.

API в итоге оказались на Railway

С API была отдельная история.

Хотя это были проекты на Next.js, они уже почти не зависели от него. API WebCatalog насчитывал около 34 000 строк кода, но только семь файлов импортировали next/server. tRPC уже использовал адаптер Fetch, а Inngest поддерживал Hono.

Мы заменили HTTP-оболочку Next.js на Hono. Эта часть оказалась на удивление небольшой.

Сложнее было решить, где всё это запускать. Обычные Workers не подходили, поскольку API используют Node.js и нативные зависимости, такие как sharp.

Сначала мы попробовали Cloudflare Containers — это позволило быстро уйти с Vercel. Но после запуска в производственной среде выяснилось, что такая операционная модель требует больше ручной настройки мощностей, чем нам тогда хотелось.

Поэтому мы снова перенесли API.

Теперь они работают на Railway как обычные долгоживущие контейнерные сервисы Node.js. Система CI (непрерывной интеграции) собирает Docker-образы и отправляет их в наш реестр, а Railway обеспечивает горизонтальное автомасштабирование.

Не всё нужно запускать на периферии сети.

Уход с Vercel означал больше ответственности

Снижение затрат потребовало компромисса.

Vercel и Next.js обеспечивали многие инфраструктурные функции на более высоком уровне. С TanStack Start и Workers мы перешли к явному управлению HTTP-кешированием. Страница рендерится, мы возвращаем заголовки кеширования, а Cloudflare кеширует ответ. Политики кеширования в браузере и на периферии сети могут различаться, в том числе в отношении выдачи устаревшего ответа с обновлением кеша в фоне.

Нам нравилось, что эти решения стали явными, но при явном управлении инфраструктурой ответственность за ошибки тоже лежит на вас.

Мы допустили несколько таких ошибок. Одно правило кеширования в производственной среде случайно распространялось на ответы серверных функций TanStack, специфичные для конкретного посетителя. Другая конфигурация кеша плохо сочеталась с механизмом перехода к index.html для маршрутов SPA. Эти ошибки напомнили нам: нельзя доказать корректность миграции, изучив только репозиторий. Производственная инфраструктура — тоже часть системы.

ИИ-агенты изменили наш подход к миграции

Большую часть реализации выполнили ИИ-агенты для написания кода, прежде всего Claude Fable 5 и Claude Opus 5.

Миграции между фреймворками особенно хорошо подходят агентам, потому что для значительной части работы уже есть чёткий образец. Перенести этот маршрут, сохранить этот URL, заменить этот API фреймворка, оставить те же метаданные, запустить проверку типов, исправить ошибки и сравнить результат со старой реализацией.

Для webcatalog.io мы вели план миграции, разбив работу на этапы: основа, страницы продуктов, страницы каталога, поиск, блог, цены, перенаправления, карты сайта и переключение на новую версию. Вместо просьбы «перенеси webcatalog.io на TanStack Start» мы давали агенту ограниченные задачи с явно заданными требованиями, которые нельзя нарушать.

Существующее приложение стало спецификацией. Задача агента заключалась в том, чтобы воспроизвести его поведение в новой архитектуре, а не переизобрести продукт.

Это сместило усилия людей с ручного переноса кода на вопросы другого рода: действительно ли этой странице нужен SSR? Какое поведение задумано намеренно? Что допустимо кешировать для всех пользователей? Какие URL должны остаться неизменными? Где должна происходить аутентификация? Когда стоит прекратить попытки заставить выбранный подход работать?

Мы по-прежнему проверяли результат, запускали сборку и проверку типов, а также вручную тестировали области повышенного риска: аутентификацию, SEO (поисковую оптимизацию), перенаправления и кеширование.

Важным изменением было не то, что ИИ написал за нас код. Важно то, что благодаря ИИ эксперименты стали дешевле.

Попробовать Astro и удалить его через пять дней стало гораздо проще обосновать. Один раз перенести API, а затем решить, что другая платформа подходит лучше, было менее болезненно. Механическая работа стала дешевле, поэтому мы могли менять направление, если архитектура оказывалась неподходящей, а не продолжать лишь потому, что уже вложили в неё слишком много.

Благодаря агентам реализация перестала быть таким дефицитным ресурсом.

А архитектура, требования, проверка изменений и подтверждение результата стали ещё важнее.

Экономия в 80% выросла примерно до 90%

После миграции расходы на веб-инфраструктуру стали примерно на 80% ниже.

Затем мы стали внимательнее следить за тем, какие запросы вообще доходят до приложений.

Значительная часть публичного интернет-трафика автоматизирована: поисковые системы, ИИ-краулеры, агенты, скрейперы, сканеры и менее дружелюбные боты. Часть такого трафика полезна, часть — нет.

Поскольку приложения находились непосредственно за Cloudflare, мы ужесточили правила безопасности, чтобы враждебный автоматизированный трафик отклонялся на периферии сети, не вызывая вычислений в приложениях и обращений к базе данных.

После этого общая экономия по сравнению с прежней конфигурацией достигла примерно 90%.

Итоговое снижение расходов обеспечили несколько факторов вместе: более низкие тарифы Cloudflare, особенно на передачу данных; меньший объём серверной работы; более подходящая среда выполнения для API; более явное кеширование; и сокращение числа ненужных запросов, вообще доходящих до приложений.

К чему мы пришли

В нашем репозитории больше нет приложений на Next.js. Большинство веб-приложений теперь представляют собой SPA на Vite + TanStack Router в Cloudflare Workers. webcatalog.io и lexibird.com используют TanStack Start на Cloudflare Workers, поскольку этим сайтам действительно полезен SSR. Наши API используют Hono + tRPC на Railway и работают в обычных контейнерах Node.js. Почти все наши фронтенд-проекты теперь находятся в экосистеме Vite.

Расходы на инфраструктуру сократились примерно на 80%. Существенный вклад в это внесла значительно более выгодная для нашего трафика экономика Cloudflare, особенно стоимость передачи данных. Фильтрация враждебного автоматизированного трафика на периферии сети довела общую экономию примерно до 90%.

Но важнее всего для нас архитектурный результат. Маркетинговые сайты получают SSR, всё, что может быть SPA, становится SPA, а API работают на настоящих серверах, когда так проще.

Мы начинали с попытки сделать Vercel дешевле.

А в итоге поняли, что большая часть архитектуры, за которую мы платили, нам вообще не нужна.