Традиційні безсерверні платформи (AWS Lambda, Google Cloud Functions) будуються на основі контейнерної віртуалізації: вхідний запит ініціює запуск мікро-віртуальної машини (Firecracker / gVisor), всередині якої стартує екземпляр Node.js із власною копією системного стека ОС. Цей підхід гарантує 100% сумісність із системними викликами POSIX, проте породжує затримки холодного старту (Cold Start) від 150 до 1200 мс і вимагає резервування сотень мегабайтів оперативної пам'яті.
Архітектура Cloudflare Workers використовує принципово інший підхід: технологію V8 Isolates. Замість створення окремих процесів операційної системи єдиний процес C++ (workerd) запускає тисячі ізольованих контекстів виконання всередині одного адресного простору.
Кожен V8 Isolate:
Розгортання Next.js 15 у цьому середовищі реалізується через компілятор @cloudflare/next-on-pages (або сучасний адаптер OpenNext for Cloudflare). Проте виконання у V8 Isolates накладає суворі архітектурні обмеження на доступні API, виключаючи використання стандартних системних бібліотек Node.js.
В архітектурі Cloudflare Workers межа між CDN та сервером застосунку повністю стирається: код рендерингу Next.js App Router виконується на тому ж фізичному прикордонному сервері, який здійснює термінацію TLS:
Клієнтський браузер
│
▼ Anycast DNS (< 20 ms RTT)
┌────────────────────────────────────────────────────────────────────────┐
│ Cloudflare Edge PoP (Global Network) │
│ │
│ [TLS 1.3 / HTTP/3 Termination] ──► [DDoS & WAF Mitigation] │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ V8 Isolate Edge Runtime │ │
│ │ - Next.js 15 App Router Server Components (RSC) │ │
│ │ - Server Actions & Edge Route Handlers │ │
│ │ - Прапорець сумісності: nodejs_compat (Web Crypto, Streams) │ │
│ └────────────────┬───────────────────────────────┬─────────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────────────────┐ ┌────────────────────────────┐ │
│ │ Cloudflare Workers KV │ │ Cloudflare R2 Bucket │ │
│ │ (Кеш сторінок ISR і теги) │ │ (Статика .next/static) │ │
│ └─────────────────────────────────┘ └────────────────────────────┘ │
└───────────────────────────────────┬────────────────────────────────────┘
│ Smart Placement / Hyperdrive
▼
┌────────────────────────────────────────────────────────────────────────┐
│ Централізована база даних (AWS RDS / Neon) │
│ Пул TCP-з'єднань через Cloudflare Hyperdrive │
└────────────────────────────────────────────────────────────────────────┘crypto.subtle) безпосередньо на CDN-вузлі до звернення до основних бекенд-сервісів.Перенесення коду Next.js на платформу Cloudflare вимагає врахування ключових обмежень середовища:
node:#У звичайному коді Node.js розробники часто використовують прямі імпорти: import crypto from 'crypto'. У Cloudflare Workers прямий доступ до системних бібліотек заблокований. Для сумісності специфікація вимагає явного використання протокольного префікса node::
import { NextResponse } from 'next/server';
// Явна декларація Edge Runtime для маршруту Next.js
export const runtime = 'edge';
// ❌ Помилка в Edge: import crypto from 'crypto'; (спроба завантажити бібліотеку ОС)
// ✅ Правильно: використання протокольного префікса при прапорці nodejs_compat
import { createHmac } from 'node:crypto';
export async function POST(request: Request): Promise<Response> {
try {
const { payload, secret } = (await request.json()) as {
payload: string;
secret: string;
};
// Варіант 1: Кросплатформний Web Standard API (Рекомендовано)
const encoder = new TextEncoder();
const keyData = encoder.encode(secret);
const messageData = encoder.encode(payload);
const cryptoKey = await crypto.subtle.importKey(
'raw',
keyData,
{ name: 'HMAC', hash: 'SHA-256' },
false,
['sign']
);
const signatureBuffer = await crypto.subtle.sign('HMAC', cryptoKey, messageData);
const webCryptoHmac = Buffer.from(signatureBuffer).toString('hex');
// Варіант 2: Використання node:crypto через поліфіл workerd
const nodeHmac = createHmac('sha256', secret).update(payload).digest('hex');
return NextResponse.json({
success: true,
webCryptoHmac,
nodeHmac,
match: webCryptoHmac === nodeHmac,
});
} catch (error) {
const message = error instanceof Error ? error.message : 'Edge Compute Error';
return NextResponse.json({ error: message }, { status: 500 });
}
}Розгортання динамічного SSR на межі мережі спричиняє класичну проблему розподілених систем — Edge-to-Database Latency Penalty:
Користувач відкриває сторінку оформлення замовлення. Anycast DNS спрямовує запит до найближчого PoP у Токіо (NRT).
SSR виконується в Токіо, але PostgreSQL розташовано у Франкфурті (fra). 4 послідовні запити до БД спричиняють 4 трансконтинентальні стрибки (4 x 220 мс = 880 мс затримки).
Алгоритм Cloudflare аналізує характер I/O та автоматично переносить виконання воркера до дата-центру у Франкфурті поруч із СУБД.
1 трансконтинентальний стрибок приносить запит до Франкфурта (220 мс), де всі 4 запити до БД виконуються локально за 2 мс. Підсумковий TTFB скорочується в 4 рази.
Нижче наведено виробничий комплекс конфігурації для проєкту Next.js 15: маніфест wrangler.jsonc із прапорцем nodejs_compat_v2, прив'язками ресурсів KV/R2, акселератором Hyperdrive та Smart Placement, а також оптимізований next.config.ts.
// wrangler.jsonc — Конфігураційний маніфест воркера Cloudflare
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "enterprise-nextjs-cloudflare",
"main": ".vercel/output/static/_worker.js",
"compatibility_date": "2026-03-01",
"compatibility_flags": [
// Активація сучасного швидкісного прошарку сумісності з Node.js APIs
"nodejs_compat_v2"
],
// Увімкнення автоматичного інтелектуального розміщення обчислень поруч із БД
"placement": {
"mode": "smart"
},
// Статичні ресурси (.next/static та загальнодоступні файли)
"assets": {
"binding": "ASSETS",
"directory": ".vercel/output/static"
},
// Розподілене сховище для кешу сторінок ISR та реєстру тегів
"kv_namespaces": [
{
"binding": "NEXT_CACHE_KV",
"id": "7b8f9a0c1d2e3f4a5b6c7d8e9f0a1b2c"
}
],
// Хмарне сховище R2 з нульовою оплатою за вихідний трафік (Zero Egress Fees)
"r2_buckets": [
{
"binding": "NEXT_MEDIA_BUCKET",
"bucket_name": "prod-media-assets"
}
],
// Акселератор пулу з'єднань до PostgreSQL
"hyperdrive": [
{
"binding": "PROD_DB",
"id": "4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d"
}
]
}// next.config.ts — Конфігурація Next.js 15 для Cloudflare Pages
import type { NextConfig } from 'next';
const nextConfig: NextConfig = {
// Строгий режим React для контролю побічних ефектів у серверних компонентах
reactStrictMode: true,
// Приховування заголовка x-powered-by
poweredByHeader: false,
// Налаштування компілятора для інтеграції з граничним кешем
experimental: {
// Підключення зовнішнього обробника кешу на базі Workers KV
incrementalCacheHandlerPath: process.env.NODE_ENV === 'production'
? require.resolve('./cache-handler-cloudflare.mjs')
: undefined,
},
images: {
// Бібліотека sharp не може виконуватися у чистому вигляді у V8 Isolates
// Оптимізація зображень делегується сервісу Cloudflare Image Resizing
unoptimized: true,
remotePatterns: [
{
protocol: 'https',
hostname: 'pub-*.r2.dev',
},
],
},
};
export default nextConfig;Підключення стандартного клієнта Prisma до Route Handler у середовищі Cloudflare Workers. Складання завершується аварійно: PrismaClientInitializationError: Binary engine for linux-musl was not found або Dynamic require of "node:fs" is not supported.
Стандартна Prisma завантажує бінарний файл рушія C++ (prisma-query-engine) і запускає його як дочірній процес через системні виклики ОС. У V8 Isolates запуск бінарних виконуваних файлів категорично заборонений.
// ❌ АНТИПАТЕРН: Спроба запуску нативного бінарника Prisma в ізолятах V8
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient(); // Падіння під час запуску
// ✅ ПРАВИЛЬНЕ РІШЕННЯ: Prisma з адаптером драйверів через Hyperdrive/Neon
import { PrismaClient } from '@prisma/client';
import { PrismaPg } from '@prisma/adapter-pg';
import { Pool } from 'pg';
// Підключення до сокета Hyperdrive через edge-сумісний драйвер
const pool = new Pool({ connectionString: env.PROD_DB.connectionString });
const adapter = new PrismaPg(pool);
const prisma = new PrismaClient({ adapter });Застосування бібліотеки bcrypt для перевірки паролів у Server Action. При спробі деплою воркер аварійно падає, оскільки bcrypt містить C++ модуль, скомпільований через Node-GYP.
// ❌ ПОМИЛКА: Нативний модуль bcrypt не підтримується у V8 Isolates
import bcrypt from 'bcrypt';
const isValid = await bcrypt.compare(password, hash);
// ✅ ПРАВИЛЬНЕ РІШЕННЯ: Використання чистого JS (bcryptjs) або Web Crypto API
import bcrypt from 'bcryptjs';
const isValid = await bcrypt.compare(password, hash);Імпорт важких монолітних бібліотек (moment.js, повні пакети lodash, застарілий AWS SDK v2). Компілятор @cloudflare/next-on-pages повертає помилку: Error: Script size exceeds the 1MB limit.
Рішення полягає у суворому tree-shaking, переході на модульні аналоги (date-fns, radash) та винесенні важкої логіки у WebAssembly (Wasm).
Спроба згенерувати звіт або PDF-файл збереженням на диск: fs.writeFileSync('/tmp/report.pdf', buffer). У Cloudflare Workers це генерує виняток TypeError: fs.writeFileSync is not a function.
Усі потокові операції повинні виконуватися виключно в пам'яті через ReadableStream та TransformStream або вивантажуватися напряму в Cloudflare R2.
Перевірка відсутності системних модулів Node.js (fs, child_process, net) та заміна нативних C++ пакетів на аналоги Wasm або Web API.
Створення wrangler.jsonc із зазначенням compatibility_date, увімкненням nodejs_compat_v2 та реєстрацією байндингів KV, R2 і Hyperdrive.
Транспіляція компонентів App Router і Server Actions у формат єдиної граничної функції _worker.js.
Тестування роботи стримінгу RSC та байндингів локально командою npx wrangler pages dev у реальному середовищі V8 Isolates.
Деплой у Cloudflare Pages, контроль метрик CPU Time та перевірка коректного переносу обчислень ближче до бази даних.