Серверные компоненты по умолчанию
Самое важное в Next.js: почему ваши компоненты по умолчанию выполняются на сервере, а не в браузере.
Server Component (серверный компонент) — компонент, который рендерится на сервере: его JavaScript не попадает в браузер, а в коде можно напрямую читать базу, файлы и секреты.
Поворот в мышлении
В обычном React весь код едет в браузер и выполняется там. В App Router всё наоборот: по умолчанию компонент серверный. Он выполняется на сервере один раз, превращается в готовый HTML, и этот HTML отправляется клиенту. Сам код компонента в браузер не уезжает.
Что это даёт на практике:
- Меньше JavaScript в браузере — быстрее загрузка и интерактивность.
- Прямой доступ к данным — можно обращаться к БД и файловой системе без отдельного API.
- Безопасность секретов — ключи и токены остаются на сервере, в браузер не попадают.
Как выглядит серверный компонент
Внешне — это обычный компонент. Особенность: он может быть async и грузить данные прямо в теле. Этот код выполнится на сервере:
// app/page.tsx — серверный компонент (по умолчанию)
import { db } from "@/lib/db";
export default async function HomePage() {
const posts = await db.posts.findMany(); // прямой доступ к БД на сервере
return (
<ul>
{posts.map((p) => (
<li key={p.id}>{p.title}</li>
))}
</ul>
);
}
Здесь блок помечен language-text, потому что обращение к БД работает только на сервере — «пощупать» в браузере его нельзя. Но идея ясна: данные читаются прямо в компоненте.
Чего серверный компонент НЕ умеет
Раз код не уезжает в браузер, в серверном компоненте нельзя использовать то, что живёт в браузере:
| Нельзя в серверном компоненте | Почему |
useState, useEffect | Это состояние и эффекты браузера |
onClick и другие обработчики | Интерактивность — это клиент |
window, localStorage | Существуют только в браузере |
Для всего интерактивного есть клиентские компоненты — о них следующий урок.
Прикинем экономию
Допустим, библиотека форматирования дат весит 30 КБ. Если она нужна только на сервере для подготовки строки, в браузер она не поедет:
const libraryKb = 30;
const componentsUsingOnServer = 8;
const saved = libraryKb; // грузим один раз на сервере, в бандл не кладём
console.log("Сэкономлено в браузерном бандле, КБ:", saved);
console.log("HTML с готовыми датами всё равно доедет до пользователя");
Вывод:
Сэкономлено в браузерном бандле, КБ: 30 HTML с готовыми датами всё равно доедет до пользователя
Итог
- В App Router компоненты по умолчанию серверные — их JS не уезжает в браузер.
- Серверный компонент может быть
asyncи напрямую читать данные и секреты. - В нём нельзя использовать состояние, эффекты, обработчики и
window.