Какие архитектурные решения Next.js навязывает вокруг rendering, state, routing, styling, data loading или deployment?
Next.js навязывает server-first рендеринг (Server Components по умолчанию), файловую маршрутизацию без возможности конфигурации, расширенный fetch API для кеширования и Vercel-ориентированный деплой.
Архитектурные решения, которые навязывает Next.js
Rendering: Server-first по умолчанию
В App Router все компоненты по умолчанию Server Components — они рендерятся на сервере и не включаются в JS-бандл клиента. Чтобы использовать useState, useEffect, браузерные API или event-handlers, нужно явно добавить директиву "use client". Это решение нужно принимать на уровне каждого компонента, а не всего приложения.
// Server Component — нет директивы, нет client JS
export default async function ProductList() {
const products = await db.query("SELECT * FROM products");
return <ul>{products.map(p => <li key={p.id}>{p.name}</li>)}</ul>;
}
// Client Component — нужен интерактив
"use client";
import { useState } from "react";
export function Counter() {
const [n, setN] = useState(0);
return <button onClick={() => setN(n + 1)}>{n}</button>;
}
State: нет глобального решения — выбирайте сами
Next.js не навязывает стейт-менеджмент. Но архитектура Server Components ограничивает варианты: Redux/Zustand store живёт только в Client Components. Если данные доступны на сервере, их часто просто передают как props и не дублируют в клиентский стор. Стандартный паттерн — Zustand для UI-состояния, React Query/SWR для серверных данных.
Routing: файловая система как API
Маршруты определяются структурой папок в app/ — это жёсткое ограничение. Нет возможности описать маршруты в конфигурационном файле, как в React Router. Следствие: рефакторинг URL = перемещение папок.
Data Loading: fetch с расширенным API
Next.js расширяет нативный fetch опциями кеширования. В Next.js 15 кеш по умолчанию отключён (no-store), в отличие от Next.js 14.
// Статические данные (кешируются навсегда)
const data = await fetch("/api/config", { cache: "force-cache" });
// Данные с ревалидацией каждые 60 секунд (ISR)
const data = await fetch("/api/products", { next: { revalidate: 60 } });
// Всегда свежие данные
const data = await fetch("/api/user", { cache: "no-store" });
Styling: любой вариант, но Tailwind — де-факто стандарт
CSS Modules, Tailwind, styled-components, Emotion — всё работает. Но CSS-in-JS библиотеки, требующие runtime (styled-components v5), несовместимы с Server Components без обёртки в Client Component.
Deployment: Vercel-first, но не только
Приложение оптимально работает на Vercel — автоматический edge runtime, Image Optimization API, ISR out of the box. На других платформах (Railway, Fly.io, Docker) нужно настраивать output: "standalone" и терять часть Vercel-специфичных фич.
// next.config.js — standalone для Docker
/** @type {import('next').NextConfig} */
const nextConfig = {
output: "standalone",
};
module.exports = nextConfig;
Подводные камни
- Граница Server/Client Component нарушается незаметно: импорт Client Component в Server Component допустим, но передача не-сериализуемых props (функций, классов) через границу вызывает ошибку в runtime.
- Кеш fetch-запросов в Next.js 14 был агрессивным по умолчанию — многие команды годами получали stale-данные, не понимая почему. В Next.js 15 это исправлено сменой дефолта.
- styled-components и Emotion требуют специальных registry-обёрток для SSR в App Router — без них стили мигают при гидрации.
- Middleware выполняется на Edge Runtime и не имеет доступа к Node.js API (fs, crypto и т.д.) — это частая причина ошибок при переносе логики из API route в middleware.
- Переход с Pages Router на App Router — не просто переименование папок. Разные модели данных, lifecycle, layouts требуют переосмысления архитектуры.
- Route Groups
(group)не влияют на URL, но если создать два файлаpage.tsxв разных группах с одинаковым итоговым URL — ошибка сборки без очевидного сообщения.
What hurts your answer
- Знать термины Next.js, но не понимать связи между абстракциями
- Объяснять поведение через отдельные примеры вместо причинной модели
- Не связывать mental model с диагностикой ошибок
What they're listening for
- Понимает ключевые абстракции Next.js
- Может предсказывать поведение системы через mental model
- Связывает модель с debugging и production decisions