Платформа Vercel являє собою спеціалізовану безсерверну інфраструктуру корпоративного рівня (Serverless PaaS), розгорнуту поверх глобальної мережі Anycast CDN та обчислювальних потужностей гіперскейлерів (переважно AWS). На відміну від класичного хостингу на віртуальних машинах (EC2, Droplets), де єдиний довгоживучий процес Node.js обробляє вхідні HTTP-з'єднання через системний сокет, Vercel декомпозує скомпільований артефакт Next.js на три ізольовані шари виконання:
fetch (Vercel Data Cache), що синхронізується між усіма PoP планети у фоновому режимі.Розуміння цієї трирівневої декомпозиції є критичним для проектування високонадійних enterprise-систем, запобігання каскадним збоям під час пікових навантажень та дотримання жорстких вимог SLA щодо затримок (TTFB) і бюджетів споживання пам'яті.
Вхідний запит від клієнта ніколи не спрямовується безпосередньо в монолітний сервер. Він проходить крізь багаторівневий маршрутизатор платформи, де кожен крок відсікає зайві затримки мережі:
Вхідний клієнтський запит (HTTPS / Anycast IP)
│
▼
┌─────────────────────────────────────────────────────────┐
│ Vercel Edge Network (PoP) │
│ - TLS 1.3 Termination, захист від DDoS │
│ - Виконання Edge Middleware (auth, routing, rewrites) │
│ - Пошук в Edge Cache (статичні файли, .next/static) │
└───────────┬─────────────────────────────────┬───────────┘
│ HIT (200 OK) │ MISS / Dynamic
▼ ▼
┌───────────────────────┐ ┌───────────────────────────────────────┐
│ Anycast Edge Cache │ │ Vercel Shared ISR / Data Cache │
│ (Assets / Images) │ │ (Глобальне персистентне сховище) │
└───────────────────────┘ └───────────────────┬───────────────────┘
│ SWR Revalidation
▼
┌───────────────────────────────────────┐
│ Serverless Function (Node.js/AWS) │
│ - SSR та RSC рендеринг App Router │
│ - Server Actions / Route Handlers │
│ - Прямий доступ до БД (Postgres) │
└───────────────────────────────────────┘x-vercel-ip-country, визначає країну користувача та здійснює внутрішній URL Rewrite на регіональний суб-шлях без додаткового мережевого стрибка до центральної бази даних.tags: ['article-1024', 'category-breaking']. Під час публікації редакційних змін у headless CMS вхідний вебхук викликає revalidateTag(), очищуючи кеш на всіх світових PoP Vercel за 300 мс.x-vercel-protection-bypass.У Next.js 15+ інженер може явно декларувати середовище виконання для кожного сегмента маршруту за допомогою Route Segment Config. Ці середовища мають принципові архітектурні відмінності:
У безсерверній архітектурі файлова система /tmp кожного інстансу Lambda є суворо ефемерною: при масштабуванні до сотень паралельних контейнерів кожен із них має повністю ізольований локальний диск. Якби Next.js зберігав згенеровані сторінки локально, виникла б критична розсинхронізація даних (Cache Drift).
Vercel вирішує цю проблему за допомогою Shared Data Cache Architecture:
Запит надходить на найближчу точку Anycast PoP. Edge Cache перевіряє наявність скомпільованого HTML/RSC вмісту.
При відсутності в кеші запит передається до найближчої Serverless Function у визначеному регіоні (наприклад, fra1 / us-east-1) для виконання RSC рендерингу.
Згенерований RSC-пейлоуд та метадані кешу (включно зі зв'язками revalidateTag) асинхронно записуються у розподілене централізоване сховище Vercel.
Зовнішній вебхук викликає revalidateTag('products'). Vercel Cache Bus миттєво розсилає команду очищення кешу на всі глобальні PoP без перескладання коду.
Критичним експлуатаційним обмеженням платформи Vercel є обмеження на розмір тіла запиту:
multipart/form-data на Route Handler або Server Action призводить до негайної помилки 413 FUNCTION_PAYLOAD_TOO_LARGE на рівні зворотного проксі Vercel ще до запуску коду функції.import { NextResponse, type NextRequest } from 'next/server';
import { put } from '@vercel/blob';
export const runtime = 'nodejs';
// 1. Клієнт запитує генерацію авторизованої сесії завантаження
export async function POST(request: NextRequest): Promise<NextResponse> {
try {
const { filename, contentType } = (await request.json()) as {
filename: string;
contentType: string;
};
if (!filename || !contentType) {
return NextResponse.json(
{ error: 'Filename and contentType are required' },
{ status: 400 }
);
}
// Валідація MIME-типів для блокування завантаження небезпечних виконуваних файлів
const allowedMimeTypes = ['image/jpeg', 'image/png', 'image/webp', 'application/pdf'];
if (!allowedMimeTypes.includes(contentType)) {
return NextResponse.json(
{ error: 'Unsupported media type' },
{ status: 415 }
);
}
// Генерація прямого токена завантаження у Vercel Blob
// Файли понад 100 МБ завантажуються безпосередньо з браузера у глобальне сховище
const blob = await put(`uploads/${crypto.randomUUID()}-${filename}`, '', {
access: 'public',
addRandomSuffix: true,
});
return NextResponse.json({ uploadUrl: blob.url });
} catch (error) {
const message = error instanceof Error ? error.message : 'Internal Server Error';
return NextResponse.json({ error: message }, { status: 500 });
}
}Нижче наведено еталонний комплекс конфігурації для виробничого репозиторію Next.js 15: маніфест vercel.json з прив'язкою обчислювальних регіонів, лімітами пам'яті та заголовками кібербезпеки, а також middleware.ts із підтримкою обходу Preview Protection для автоматизованих тестів.
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"framework": "nextjs",
"cleanUrls": true,
"trailingSlash": false,
"regions": ["fra1"],
"functions": {
"app/api/**/*": {
"memory": 1024,
"maxDuration": 60
},
"app/**/*": {
"memory": 1536,
"maxDuration": 30
}
},
"headers": [
{
"source": "/(.*)",
"headers": [
{
"key": "X-Content-Type-Options",
"value": "nosniff"
},
{
"key": "X-Frame-Options",
"value": "DENY"
},
{
"key": "Referrer-Policy",
"value": "strict-origin-when-cross-origin"
},
{
"key": "Permissions-Policy",
"value": "camera=(), microphone=(), geolocation=(), browsing-topics=()"
},
{
"key": "Strict-Transport-Security",
"value": "max-age=63072000; includeSubDomains; preload"
}
]
},
{
"source": "/_next/static/(.*)",
"headers": [
{
"key": "Cache-Control",
"value": "public, max-age=31536000, immutable"
}
]
}
]
}// middleware.ts — Захист та маршрутизація на рівні Edge
import { NextResponse, type NextRequest } from 'next/server';
export const config = {
matcher: [
/*
* Застосовуємо middleware до всіх шляхів, крім:
* - _next/static (статичні бандли)
* - _next/image (сервіс оптимізації зображень)
* - favicon.ico, robots.txt, sitemap.xml
*/
'/((?!_next/static|_next/image|favicon.ico|robots.txt|sitemap.xml).*)',
],
};
export function middleware(request: NextRequest): NextResponse {
const response = NextResponse.next();
// 1. Отримання даних про фізичну локацію клієнта із заголовків Anycast Edge
const country = request.headers.get('x-vercel-ip-country') ?? 'US';
const city = request.headers.get('x-vercel-ip-city') ?? 'Unknown';
response.headers.set('x-client-geo-country', country);
response.headers.set('x-client-geo-city', encodeURIComponent(city));
// 2. Механізм обходу Deployment Protection для CI/CD та E2E-тестів (Playwright)
// У Preview Environments Vercel вимагає SSO або пароль.
// Криптографічний секрет дозволяє тестовому раннеру безперешкодно виконувати тести.
const bypassSecret = process.env.VERCEL_AUTOMATION_BYPASS_SECRET;
const providedBypassHeader = request.headers.get('x-vercel-protection-bypass');
if (bypassSecret && providedBypassHeader === bypassSecret) {
// Встановлюємо системну сесійну куку Vercel для авторизації тестів
response.cookies.set('__vdpl', bypassSecret, {
path: '/',
httpOnly: true,
secure: true,
sameSite: 'none',
maxAge: 3600, // 1 година на прогін тестів
});
}
// 3. Динамічна генерація криптографічного Nonce для Content Security Policy (CSP)
const nonce = Buffer.from(crypto.randomUUID()).toString('base64');
const cspHeader = `
default-src 'self';
script-src 'self' 'nonce-${nonce}' 'strict-dynamic';
style-src 'self' 'nonce-${nonce}';
img-src 'self' blob: data: https:;
font-src 'self';
connect-src 'self' https://vitals.vercel-insights.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
`.replace(/\s{2,}/g, ' ').trim();
response.headers.set('x-nonce', nonce);
response.headers.set('Content-Security-Policy', cspHeader);
return response;
}Створення ендпоінта /api/upload за допомогою request.formData() для завантаження файлів розміром 20–50 МБ (відео, важкі PDF або архіви). Локально в середовищі Node.js код працює ідеально, проте на Vercel негайно падає.
Зворотний проксі Anycast Vercel миттєво обриває з'єднання з кодом 413 FUNCTION_PAYLOAD_TOO_LARGE, оскільки базовий шлюз AWS Lambda накладає жорстке обмеження на тіло запиту у 4.5 МБ.
// ❌ АНТИПАТЕРН: Запит переривається шлюзом ще до виклику коду функції
export async function POST(request: Request) {
const formData = await request.formData();
const file = formData.get('largeFile') as File; // Помилка 413, якщо файл > 4.5 МБ
await saveToDatabase(file);
return NextResponse.json({ ok: true });
}
// ✅ ПРАВИЛЬНЕ РІШЕННЯ: Client-Side Direct Upload через Presigned URL
// Серверний маршрут лише генерує короткоживучий токен доступу (розмір кілька байтів),
// а браузер завантажує байти безпосередньо в S3 або Vercel Blob.Спроба виконати перевірку прав користувача або блокування сесії через пряме звернення до Prisma ORM або pg пулу всередині middleware.ts.
Edge Middleware виконується в ізольованому рантаймі V8 Isolates, де повністю відсутній системний модуль net для створення прямих TCP-сокетів. Складання завершується критичною помилкою: Module not found: Can't resolve 'net'.
// ❌ ФАТАЛЬНА ПОМИЛКА у middleware.ts: Edge Runtime не підтримує сирі TCP-сокети
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient(); // Крах рантайму
export async function middleware(req: NextRequest) {
const user = await prisma.user.findUnique({ where: { id: '...' } });
return NextResponse.next();
}
// ✅ ПРАВИЛЬНЕ РІШЕННЯ: Валідація криптографічного підпису JWT на межі мережі без звернення до БД,
// або використання з'єднань через HTTP-проксі (Neon Serverless Driver, Upstash Redis).В Enterprise-підписці для захисту передрелізних збірок вмикається пароль або SSO на Preview Environments. Після цього регулярні запуски Playwright у GitHub Actions починають масово падати з помилкою 401 Unauthorized, отримуючи сторінку входу Vercel замість тестованого інтерфейсу.
// ❌ ПОМИЛКА: Запуск тестів проти захищеного Preview URL без bypass-заголовків
// playwright.config.ts
export default defineConfig({
use: {
baseURL: process.env.VERCEL_PREVIEW_URL, // Повертає HTTP 401 Unauthorized
},
});
// ✅ ПРАВИЛЬНЕ НАЛАШТУВАННЯ: Ін'єкція Vercel Protection Bypass заголовків у контекст браузера
// playwright.config.ts
export default defineConfig({
use: {
baseURL: process.env.VERCEL_PREVIEW_URL,
extraHTTPHeaders: {
'x-vercel-protection-bypass': process.env.VERCEL_AUTOMATION_BYPASS_SECRET || '',
'x-vercel-set-bypass-cookie': 'true',
},
},
});За замовчуванням Vercel розгортає Serverless Functions у регіоні Північна Вірджинія, США (iad1 / us-east-1). Якщо база даних PostgreSQL (наприклад, AWS RDS) розташована у Франкфурті (eu-central-1), кожен SSR-запит або Server Action здійснює трансатлантичний перехід із затримкою 100–120 мс на кожен SQL-запит.
Для усунення проблеми обов'язково вказуйте regions: ["fra1"] у файлі vercel.json, розташовуючи обчислення поруч із базою даних.
Визначення фізичного розташування первинної бази даних та фіксація регіону виконання Serverless Functions у vercel.json (наприклад, fra1 або hnd1) для мінімізації затримок.
Винесення важких операцій введення-виведення та рендерингу RSC у Node.js Serverless, а легкої маршрутизації, геотаргетингу та валідації токенів — в Edge Middleware.
Впровадження детермінованих тегів кешування для fetch-запитів та реєстрація вхідних вебхуків для виклику revalidateTag() без перескладання додатку.
Активація Vercel Deployment Protection (SAML/SSO), конфігурація VERCEL_AUTOMATION_BYPASS_SECRET та передача bypass-заголовків у тестові набори Playwright.
Підключення Vercel Speed Insights та трейсингу OpenTelemetry для оперативного контролю холодних стартів, TTFB та тривалості виконання функцій.