Я использую Next.js 14 (App Router) и Supabase для аутентификации с Postgres, но чаще разворачиваю с Vercel
Неделя тестирования одного и того же проекта как на Vercel, так и на Cloudflare Workers показывала значительное преимущество последнего, особенно в плане задержки и более удобного бесплатного тарифа.
Ранее развёртывание приложений Next.js на Cloudflare считалось непростой задачей — существовавшие решения, такие как Cloudflare Pages, не поддерживали полноценный функционал Next.js и часто возникали проблемы с инструментами вроде next-on-pages.
С появлением @opennextjs/cloudflare всё изменилось, позволяя без особых усилий компилировать стандартное приложение Next.js в Cloudflare Worker и использовать такие функции, как SSR, ISR, middleware и компонент Image.
В этом руководстве я поделюсь шагами, которые я использовал для развёртывания приложения Next.js + Supabase на Cloudflare Workers — это именно тот runbook, который я бы хотел видеть в самом начале
- Cloudflare Workers vs Vercel: что выбрать для Next.js?
- Ключевые преимущества Cloudflare Workers
- Компромиссы, которые стоит учитывать
- Предварительные требования
- Установка Wrangler (CLI Cloudflare)
- Стек технологий
- Шаг 1 — Установка адаптера Cloudflare
- Шаг 2 — Подключение OpenNext к next dev
- Шаг 3 — Настройка локального окружения с .dev.vars
- Пример: .dev.vars.example (фиксируется в репозитории)
- Настройка локального окружения
- Зачем использовать оба файла?
- Обновление .gitignore
- Шаг 4 — Развёртывание приложения с локальной машины
- Шаг 5 — Загрузка секретов в Worker
- Шаг 6 — CI/CD с GitHub Actions для Cloudflare Workers
- Необходимые секреты репозитория GitHub
- Шаг 7 — Обновление проекта (ежедневный рабочий процесс)
- Изменение кода
- Обновление переменных окружения / секретов
- Типичные ошибки при деплое Next.js на Cloudflare Workers
- Ответы на эти вопросы могут быть для вас полезными
Cloudflare Workers vs Vercel: что выбрать для Next.js?
При развёртывании Next.js обычно выбираю Vercel — устойчиво интегрируется с Next.js
Но Cloudflare Workers предоставляет убедительную альтернативу, особенно когда важна глобальная производительность и экономическая эффективность
Ключевые преимущества Cloudflare Workers
Меньшая задержка по всему миру. Cloudflare запускает ваше приложение в сотнях граничных точек присутствия (edge PoP), сокращая время отклика для пользователей по всему миру.
Минимальные холодные старты. Благодаря изолятам V8 функции запускаются практически мгновенно.
Экономическая эффективность. Бесплатный тариф достаточно щедрый для портфолио, блогов и многих небольших и средних приложений.
Компромиссы, которые стоит учитывать
Cloudflare Workers используют среду выполнения на изолятах V8, а не полноценную среду Node.js. Это означает:
- Некоторые API Node.js, такие как
fsилиchild_process, недоступны - Нативные бинарные файлы или определённые библиотеки могут не работать
Тем не менее для большинства современных стеков — таких как Next.js + Supabase + Stripe + Resend — это ограничение редко становится проблемой.
Если кратко: выбирайте Vercel для простоты развёртывания Next.js, а Cloudflare Workers — для оптимизации производительности и более гибкого масштабирования.
По этой теме полезно отдельно посмотреть Составьте еженедельное расписание занятий, чтобы расширить контекст и сравнить подходы.
По этой теме полезно отдельно посмотреть Создание динамических форм в React и Next.js, чтобы расширить контекст и сравнить подходы.
Предварительные требования
Прежде чем начать, убедитесь, что у вас настроено следующее. Большинство из этих шагов занимают всего несколько минут:
- Node.js 18+ и pnpm 9+ (можно также использовать npm или yarn, но в этом руководстве используется pnpm)
- Аккаунт Cloudflare 👉 https://dash.cloudflare.com/sign-up
- Аккаунт Supabase (если ваше приложение использует базу данных) 👉 https://supabase.com
- Репозиторий GitHub для вашего проекта (потребуется позже для настройки CI/CD)
- Доменное имя (необязательно) — по умолчанию вы получите бесплатный URL вида
*.workers.dev
Установка Wrangler (CLI Cloudflare)
Мы будем использовать Wrangler для сборки и развёртывания приложения:
pnpm add -g wrangler
Стек технологий
Вот технологический стек, используемый в этом проекте:
- Next.js (v14.2.x): использует App Router с Edge runtime для публичных маршрутов и маршрутов панели управления
- Supabase: обеспечивает аутентификацию, базу данных Postgres и безопасность на уровне строк (RLS — Row Level Security)
- Tailwind CSS + UI-утилиты: для стилизации, а также лёгкая анимация с помощью Framer Motion
- Cloudflare Workers: развёртывание на основе @opennextjs/cloudflare и wrangler
- GitHub Actions: используется для автоматизации CI/CD и развёртываний
Примечание: если вы используете Next.js 15 или более позднюю версию, вы можете убрать флаг --dangerouslyUseUnsupportedNextVersion из скрипта сборки, поскольку он требуется только для определённых конфигураций Next.js 14.
Шаг 1 — Установка адаптера Cloudflare
Из вашего существующего проекта Next.js установите адаптер OpenNext вместе с Wrangler:
pnpm add @opennextjs/cloudflare
pnpm add -D wrangler
Затем добавьте скрипты развёртывания в package.json:
«json { "scripts": { "dev": "next dev", "build": "next build", "start": "next start", "lint": "next lint", "cloudflare-build": "opennextjs-cloudflare build --dangerouslyUseUnsupportedNextVersion", "preview": "pnpm cloudflare-build && opennextjs-cloudflare preview", "deploy": "pnpm cloudflare-build && wrangler deploy", "upload": "pnpm cloudflare-build && opennextjs-cloudflare upload", "cf-typegen": "wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts" } } «
Что делает каждый скрипт:
| Скрипт | Назначение |
|---|---|
cloudflare-build | Компилирует Next.js в формат Cloudflare Worker |
preview | Собирает и запускает локальный эмулятор через Miniflare |
deploy | Собирает и публикует Worker на Cloudflare |
upload | Загружает только ресурсы без полного деплоя |
cf-typegen | Генерирует TypeScript-типы для привязок Cloudflare |
Обратите внимание: @cloudflare/next-on-pages на основе Pages — это другой инструмент. Мы не используем Pages — мы развёртываем как настоящий Worker. Не смешивайте эти два подхода.
Шаг 2 — Подключение OpenNext к next dev
Чтобы pnpm dev мог читать ваши привязки Cloudflare (переменные окружения, R2, KV, D1 и другие) так же, как это делает продакшн, отредактируйте next.config.mjs:
/** @type {import('next').NextConfig} */
const nextConfig = {};
if (process.env.NODE_ENV !== "production") { const { initOpenNextCloudflareForDev } = await import( "@opennextjs/cloudflare" ); initOpenNextCloudflareForDev();
}
export default nextConfig;
Мы вызываем это только в режиме разработки, чтобы next build оставался быстрым и CI не запускал экземпляр Miniflare впустую.
Шаг 3 — Настройка локального окружения с .dev.vars
При локальной работе с Cloudflare Workers Wrangler использует файл .dev.vars для хранения переменных окружения — вместо .env.local, используемого Next.js.
Простой и надёжный подход — хранить в репозитории файл-пример и игнорировать реальный файл.
Пример: .dev.vars.example (фиксируется в репозитории)
NEXT_PUBLIC_SUPABASE_URL="https://YOUR-PROJECT-ref.supabase.co"
NEXT_PUBLIC_SUPABASE_ANON_KEY="YOUR-ANON-KEY"
NEXT_PUBLIC_DASHBOARD_DEFAULT_EMAIL="admin@example.com"
Настройка локального окружения
Выполните следующие команды:
cp .dev.vars.example .dev.vars
cp .dev.vars .env.local
.dev.varsиспользуется Wrangler (wrangler dev).env.localиспользуется Next.js (next dev)
Зачем использовать оба файла?
next dev читает из .env.local, а wrangler dev (используется в pnpm preview) читает из .dev.vars. Синхронизация обоих файлов обеспечивает одинаковое поведение приложения в режиме разработки и при запуске в среде выполнения Cloudflare.
Обновление .gitignore
Убедитесь, что эти файлы игнорируются:
.dev.vars
.env.local
Шаг 4 — Развёртывание приложения с локальной машины
Как только pnpm preview работает корректно, вы готовы развернуть приложение:
pnpm deploy
Под капотом это выполняет:
pnpm cloudflare-build && wrangler deploy
В первый раз Wrangler:
- Скомпилирует ваше приложение в
.open-next/worker.js - Загрузит скрипт и ресурсы на Cloudflare
- Выведет ваш живой URL, например
https://portfolio.<your-account>.workers.dev
Откройте его в браузере — вы на граничной сети Cloudflare в 330+ городах. Страница должна отдаваться с TTFB менее 100 мс из любой точки мира.
Шаг 5 — Загрузка секретов в Worker
Локальный .dev.vars не загружается командой wrangler deploy. Секреты нужно загружать явно:
wrangler secret put NEXT_PUBLIC_SUPABASE_URL
wrangler secret put NEXT_PUBLIC_SUPABASE_ANON_KEY
wrangler secret put NEXT_PUBLIC_DASHBOARD_DEFAULT_EMAIL
Каждая команда запрашивает значение и сохраняет его в зашифрованном виде на Cloudflare. Или сделайте это визуально:
Cloudflare Dashboard → Workers & Pages → ваш worker → Settings → Variables and Secrets → Add
Переменные NEXT_PUBLIC_* встраиваются в клиентский бандл во время сборки, поэтому они также должны быть доступны при выполнении pnpm cloudflare-build — локально это ваш .env.local, в CI — см. шаг 6.
Шаг 6 — CI/CD с GitHub Actions для Cloudflare Workers
Как только локальное развёртывание работает, следующий шаг — автоматизация, чтобы каждый push в ветку main автоматически обновлял продакшн.
С этим рабочим процессом:
- Pull request’ы будут запускать проверки валидации
- Продакшн-развёртывания происходят только после успешных сборок
- Сломанный код никогда не попадает на живой сайт
Создайте следующий файл внутри вашего проекта:
name: Deploy to Cloudflare Workers
on: push: branches: [main] pull_request: branches: [main]
jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: 18
cache: pnpm
- run: pnpm install
- name: Build and Deploy
if: github.ref == 'refs/heads/main'
run: pnpm deploy
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }}
NEXT_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_ANON_KEY }}
NEXT_PUBLIC_DASHBOARD_DEFAULT_EMAIL: ${{ secrets.NEXT_PUBLIC_DASHBOARD_DEFAULT_EMAIL }}
- name: Lint and Build (PR check)
if: github.ref != 'refs/heads/main'
run: pnpm lint && pnpm build
Необходимые секреты репозитория GitHub
Перейдите в GitHub repo → Settings → Secrets and variables → Actions → New repository secret и добавьте:
| Секрет | Где взять |
|---|---|
NEXT_PUBLIC_DASHBOARD_DEFAULT_EMAIL | Ваше значение по умолчанию |
Запушьте в main, и через примерно 90 секунд всё будет в продакшне. PR’ы запускают только lint и build, поэтому сломанный код никогда не попадает в продакшн.
Шаг 7 — Обновление проекта (ежедневный рабочий процесс)
После первоначальной настройки цикл становится скучно простым — что и является целью. Вот что я делаю изо дня в день:
Изменение кода
git checkout -b feat/new-section
# ...редактируем файлы...
pnpm dev # итерируем локально
pnpm preview # финальная проверка в среде выполнения Worker
git commit -am "feat: add new section"
git push origin feat/new-section
Откройте PR и убедитесь, что задание выполняется. Затем проверьте, смержите и задеплойте. Задание автоматически отправляет изменения на Cloudflare.
Обновление переменных окружения / секретов
# Локально
nano .dev.vars
# Продакшн
wrangler secret put NEXT_PUBLIC_SUPABASE_URL
# ...и т.д.
Типичные ошибки при деплое Next.js на Cloudflare Workers
Несколько граблей, на которые я наступил сам и которые стоит обойти заранее.
Смешение Pages и Workers. @cloudflare/next-on-pages и @opennextjs/cloudflare — разные инструменты с разными моделями развёртывания. Если вы видите в документации упоминание Cloudflare Pages, это другой путь. Здесь мы работаем только с Workers.
*Переменные NEXT_PUBLIC_ не попадают в сборку.** Эти переменные встраиваются в бандл на этапе cloudflare-build, а не в рантайме. Если вы добавили их в Cloudflare Dashboard, но не передали в CI через env: в GitHub Actions — в продакшне они будут пустыми.
Использование Node.js API, недоступных в V8-изоляторах. Если ваш код или зависимость использует fs, path в серверном контексте или child_process — Worker упадёт. Проверяйте совместимость библиотек заранее через pnpm preview.
Забытый .dev.vars при смене машины. Файл намеренно исключён из репозитория. При работе на новой машине нужно заново создать его из .dev.vars.example и заполнить значениями.
Когда я начинал эту миграцию, я нервничал из-за ухода с Vercel — опыт разработчика там действительно превосходный. Но как только выходишь за рамки хобби-сайта, экономика Cloudflare и граничная производительность несравнимы.
С @opennextjs/cloudflare опыт разработчика также подтянулся: мой цикл
pnpm devидентичен привычному,pnpm previewимитирует продакшн, аgit pushразворачивает приложение глобально примерно за 90 секунд.Если вы откладывали переход, потому что старая история с Cloudflare Pages + Next.js была сложной — та эпоха закончилась. Попробуйте этот runbook на стороннем проекте в эти выходные и убедитесь сами.
Ответы на эти вопросы могут быть для вас полезными
Можно ли использовать этот подход с Next.js 15?
Да. Для Next.js 15 и выше флаг --dangerouslyUseUnsupportedNextVersion в скрипте cloudflare-build можно убрать — он требуется только для определённых конфигураций Next.js 14.
Чем отличается развёртывание через Cloudflare Pages от Cloudflare Workers?
Pages использует адаптер @cloudflare/next-on-pages и имеет ограничения по поддержке функций Next.js. Workers с @opennextjs/cloudflare — это полноценный Worker-скрипт с поддержкой SSR, ISR и middleware. Это разные модели развёртывания, и смешивать их не стоит.
Что делать, если приложение падает из-за недоступного Node.js API?
Запустите pnpm preview локально — Miniflare эмулирует среду выполнения Cloudflare и покажет ошибку до деплоя. Затем найдите зависимость, использующую недоступный API, и замените её на совместимую альтернативу.
Как обновить секрет в продакшне без повторного деплоя?
Выполните wrangler secret put ИМЯ_ПЕРЕМЕННОЙ — Cloudflare обновит значение без пересборки Worker. Но помните: переменные NEXT_PUBLIC_* встраиваются в бандл при сборке, поэтому для их обновления потребуется новый деплой.
Сколько стоит Cloudflare Workers для небольшого проекта?
Бесплатный тариф включает 100 000 запросов в день и нулевую стоимость холодных стартов. Для портфолио, блога или MVP этого более чем достаточно. Платный тариф Workers Paid начинается от $5 в месяц и даёт 10 миллионов запросов.



