Назад к блогу

Next.js 15: Полное руководство по Server Components

Pavel Levdin30.03.202615 мин
Next.js 15: Полное руководство по Server Components

В 2026 году 78% новых Next.js проектов используют App Router с Server Components. Это не тренд — это новая парадигма фулстек-разработки, которая меняет подход к производительности, SEO и архитектуре React-приложений.

Что вы узнаете:

  • ✅ Как работает гидратация и почему RSC её устраняют
  • ✅ Паттерны разделения Client/Server компонентов
  • ✅ Кэширование и стриминг в Next.js 15
  • ✅ Миграция с Pages Router на App Router

1. Архитектура Server Components

React Server Components (RSC) — это компоненты, которые рендерятся исключительно на сервере. Они никогда не попадают в клиентский бандл, что даёт три ключевых преимущества:

Характеристика Server Component Client Component
Где выполняется Только сервер (Node.js/Edge) Сервер + Браузер
Размер бандла 0 KB (не отправляется клиенту) Весь код компонента
Доступ к БД/API ✅ Прямой доступ ❌ Только через fetch/API routes
Интерактивность ❌ Нет useState/useEffect ✅ Полная интерактивность
SEO ✅ Полный HTML в ответе ⚠️ Требует SSR/SSG

💡 Совет: По умолчанию все компоненты в App Router — Server Components. Чтобы сделать компонент клиентским, добавьте директиву 'use client' в начало файла. Не используйте её без необходимости — каждый клиентский компонент увеличивает размер JavaScript-бандла.

2. Гидратация и Zero-Bundle-Size

Традиционный SSR (Pages Router) работает по схеме: рендер на сервере → отправка HTML → загрузка JS → гидратация → интерактивность. Проблема в том, что React должен «оживить» весь HTML, сравнивая виртуальный DOM с реальным.

С Server Components этот процесс меняется радикально:

// app/page.tsx — Server Component по умолчанию
import { db } from '@/lib/db' // ✅ Директ импорт на сервере

export default async function ProductPage() {
  // ✅ Прямой запрос к БД без API слоя
  const products = await db.query('SELECT * FROM products')

  return (
    

Каталог товаров

{products.map(p => ( ))}
) }

В этом примере db.query выполняется только на сервере. Клиент получает готовый HTML без кода для работы с базой данных. Экономия: ~15-40 KB JavaScript на типичной странице каталога.

⚠️ Важно: Server Components не могут использовать браузерные API (window, document, localStorage) и React-хуки состояния (useState, useEffect, useContext). Для интерактивных элементов создавайте клиентские компоненты и импортируйте их в Server Components.

3. Паттерны разделения компонентов

Граница между сервером и клиентом — ключевое архитектурное решение. Вот проверенные паттерны из production-проектов 2026 года:

Паттерн «Листья клиента»

Делайте Server Components «стволом» дерева, а интерактивные элементы — «листьями»:

// app/product/[id]/page.tsx — Server Component
import { AddToCartButton } from './AddToCartButton' // Client Component
import { db } from '@/lib/db'

export default async function ProductPage({ params }: { params: { id: string } }) {
  const product = await db.products.findUnique({ where: { id: params.id } })

  return (
    

{product.name}

{product.description}

{/* ✅ Только кнопка — клиентский компонент */}
) }

Паттерн «Составной компонент»

Передавайте Server Components как children в Client Components:

// components/Modal.tsx — Client Component
'use client'

export function Modal({ children, trigger }: { children: React.ReactNode, trigger: React.ReactNode }) {
  const [open, setOpen] = useState(false)
  return (
    <>
      
      {open && 
{children}
} ) } // app/page.tsx — Server Component import { Modal } from '@/components/Modal' import { ProductList } from './ProductList' // Server Component export default function Page() { return ( {/* ✅ ProductList рендерится на сервере, но показывается в клиентском модале */} ) }

💡 Совет: Используйте анализатор бандла @next/bundle-analyzer, чтобы увидеть, какие компоненты попадают в клиентский чанк. Цель: минимизировать 'use client' директивы на верхних уровнях дерева.

4. Кэширование и Partial Prerendering

Next.js 15 принёс революционную функцию — Partial Prerendering (PPR). Это гибрид статической генерации и динамического стриминга:

// next.config.js
module.exports = {
  experimental: {
    ppr: true, // Включаем Partial Prerendering
  },
}

// app/page.tsx
import { Suspense } from 'react'
import { StaticHeader } from './StaticHeader' // Статический компонент
import { DynamicReviews } from './DynamicReviews' // Динамический компонент

export default function Page() {
  return (
    <>
      {/* ✅ Предрендерится при сборке */}
      

      {/* 🔄 Стримится при запросе с fallback */}
      }>
        
      
    
  )
}

Результат: Time to First Byte (TTFB) снижается на 60-80% по сравнению с чистым SSR, а пользователи видят контент мгновенно.

Стратегия Когда использовать TTFB
Static Generation Контент не меняется (документация, лендинги) ~50ms (CDN)
Partial Prerendering Смешанный контент (e-commerce, блоги) ~100-200ms
Dynamic Streaming Персонализированный контент (дашборды) ~200-500ms
Traditional SSR Legacy Pages Router проекты ~300-800ms

5. Миграция с Pages Router

По данным опроса State of React 2026, 64% компаний уже мигрировали или находятся в процессе перехода на App Router. Вот пошаговый план:

// 1. Параллельная маршрутизация (существующий код работает)
app/
├── (marketing)/     # Новые страницы на App Router
│   ├── page.tsx
│   └── about/page.tsx
├── api/             # API Routes остаются в pages/api/
└── ...

pages/               # Старые страницы работают без изменений
├── index.tsx
├── about.tsx
└── api/

Этап 1: Создайте папку app/(marketing) для новых страниц. Скобки в названии исключают сегмент из URL.
Этап 2: Переносите страницы по одной, начиная с простых (статический контент).
Этап 3: Для сложных страниц используйте инкрементальный перенос компонентов.

⚠️ Важно: getServerSideProps и getStaticProps не работают в App Router. Данные запрашивайте напрямую в компонентах через fetch или ORM. Для кэширования используйте fetch('/api', { next: { revalidate: 60 } }) или unstable_cache.

6. Production-готовые паттерны

Обработка ошибок

// app/error.tsx — Error Boundary для сегмента
'use client'

export default function ErrorBoundary({ error, reset }: { error: Error, reset: () => void }) {
  return (
    

Что-то пошло не так

) } // app/not-found.tsx — 404 страница export default function NotFound() { return (

Страница не найдена

На главную
) }

Loading состояния

// app/loading.tsx — Показывается автоматически при загрузке
export default function Loading() {
  return 
Загрузка...
} // Или гранулярно с Suspense import { Suspense } from 'react' }>

💡 Совет: Используйте loading.tsx для немедленной обратной связи при навигации. Next.js автоматически показывает его при переходе между страницами, что улучшает воспринимаемую производительность (perceived performance).

Готовы перейти на Next.js 15?

Мы помогаем командам мигрировать на App Router без downtime. Аудит текущей архитектуры, поэтапный перенос, оптимизация Core Web Vitals.

Заключение

Next.js 15 с Server Components — это не просто новая версия фреймворка, а фундаментальный сдвиг в архитектуре веб-приложений. Устранение гидратации, zero-bundle-size компоненты и Partial Prerendering дают реальные бизнес-преимущества: скорость, SEO, снижение инфраструктурных затрат.

Ключевые принципы для production:

  • Server First — начинайте с Server Components, добавляйте клиентскую интерактивность только где нужно
  • Гранулярность — чем ниже в дереве 'use client', тем меньше бандл
  • PPR — используйте Partial Prerendering для сложных страниц
  • Инкрементальность — мигрируйте постепенно, страница за страницей

Следующая эра React уже здесь. Не оставайтесь на Pages Router — будущее за Server Components! 🚀

Поделиться:
P

Pavel Levdin

Full-Stack разработчик с 10+ годами опыта. Специализируюсь на React, Next.js и современной веб-разработке.

30.03.202615 мин

Подпишитесь в Телеграм

Получайте новые статьи и обновления прямо в мессенджер

Подписаться