Next.js: полное руководство для разработчиков
Next.js — это метафреймворк для React, созданный компанией Vercel (ранее известной как Zeit) в 2016 году, который решает множество головных болей разработчиков, связанных с построением современных веб-приложений. По сути, это такой React на стероидах — со всеми преимуществами оригинальной библиотеки, но с добавлением серверного рендеринга, статической генерации, автоматической маршрутизации и других приятных бонусов, о которых обычный React-разработчик может только мечтать.

некст.js идеально подойдет разработчикам, создающим от простых лендингов до сложных корпоративных приложений, онлайн-магазинов и любых других проектов, где важна скорость, SEO и пользовательский опыт. Если вы устали объяснять заказчикам, почему Google не видит контент их React-приложения, Next.js может стать вашим лучшим другом — или, по крайней мере, надежным попутчиком в мире современной веб-разработки.
- Основные преимущества
- Установка и настройка Next.js
- Основы работы
- Работа с данными в Next.js
- Маршрутизация и динамические страницы
- Работа с макетами (layouts) и общими компонентами
- Оптимизация производительности и SEO в Next.js
- Работа со стилями в Next.js
- {title}
- Деплой и развертывание Next.js-приложений
- Заключение
- Рекомендуем посмотреть курсы по JavaScript разработке
Основные преимущества
Что делает его удобным для разработчиков?
Next.js — это как швейцарский нож для веб-разработчика, который устал собирать собственный велосипед из деталей, разбросанных по всему npm-реестру. И если вы когда-нибудь пытались настроить с нуля React-приложение с роутингом, SSR и оптимизацией производительности, то знаете, что это примерно как собрать ИКЕА-шкаф без инструкции — теоретически возможно, но заставляет пересмотреть все жизненные решения, приведшие вас к этому моменту.
Основные фишки, заставляющие разработчиков пускать слюни:
SSR (Server-Side Rendering) — ваши страницы рендерятся на сервере, а не заставляют смартфон вашей бабушки превращаться в портативную печку при загрузке сайта. Плюс поисковые роботы могут индексировать контент без необходимости выполнять JavaScript — они ведь тоже ленивые, как и мы с вами.
Статическая генерация (SSG) — страницы генерируются заранее, что делает их загрузку молниеносной. Представьте, что вы печёте пиццу не тогда, когда клиент голоден, а заранее — и просто достаёте готовую из холодильника, когда он приходит.
Встроенная маршрутизация — создайте файл в папке pages, и — вуаля! — у вас есть новый URL. Никаких дополнительных библиотек, никакой настройки, никаких седых волос.
API-роуты — создавайте бэкенд в том же проекте, что и фронтенд. Потому что микросервисы — это прекрасно, но иногда хочется просто написать простую функцию для обработки формы, не разворачивая при этом отдельный бэкенд-сервер.
Оптимизация изображений — автоматическое изменение размера, форматирование и ленивая загрузка картинок. Больше никаких 5МБ PNG-файлов, убивающих мобильный трафик ваших пользователей.
Next.js против «чистого» React: ключевые отличия
Параметр | Next.js | «Чистый» React |
---|---|---|
Рендеринг | SSR, SSG,ISR, CSR — выбирайте как в ресторане | Только CSR — съешь свой JS-бандл целиком или останься голодным |
Маршрутизация | Встроенная, основанная на файловой системе — положил файл, получил URL | Нужна отдельная библиотека (React Router) и куча настроек |
SEO | Отличная индексация благодаря SSR/SSG | «Google, пожалуйста, подожди пока загрузится мой JavaScript» |
Производительность | Оптимизирована из коробки | «Это работает на моей машине с 32ГБ RAM» |
Настройка | Минимальная — фокус на разработке, а не на конфигурации | Webpack + Babel + роутер + состояние + кэширование + … (вставьте бесконечный список) |
Деплой | Оптимизирован для Vercel, но работает везде | Требует дополнительных настроек сервера и сборки |
Установка и настройка Next.js
Для начала убедитесь, что у вас установлен Node.js — желательно версия, которая не вызывает у современных разработчиков нервный смех. Теперь откройте терминал — да, ту страшную черную штуку с мигающим курсором, которой пугают детей перед сном — и выполните:
npx create-next-app@latest my-amazing-app
Где my-amazing-app — это гениальное название вашего будущего стартапа-единорога, который вы продадите за миллиарды (ну, или хотя бы покажете в портфолио).
Во время установки вам зададут несколько вопросов — примерно как в квесте, где от ваших ответов зависит будущее персонажа. Хотите TypeScript? Да или нет? Tailwind CSS? ESLint? Директория src? App Router? Выбирайте с умом — или просто жмите Enter, принимая дефолтные значения, как и 90% разработчиков, будем честны.
После завершения установки вы получите базовый шаблон проекта, который, на удивление, уже работает. Внутри вас ждет примерно следующая структура:
- pages/ — здесь живут ваши страницы (если вы выбрали Pages Router).
- app/ — альтернативная структура для App Router (новинка Next.js 13+).
- public/ — место для статических файлов, которые вы хотите показать миру.
- src/ — опциональная папка для исходников (если вы выбрали эту опцию).
- styles/ — CSS-файлы, потому что даже в 2025 мы все еще пишем CSS.
- next.config.js — файл конфигурации, который вы открываете с надеждой и закрываете с недоумением.
- package.json — список зависимостей, которые будут расти как снежный ком.
Чтобы запустить ваш новый проект, выполните:
cd my-amazing-app npm run dev
И — о, чудо! — на localhost:3000 вас встретит стартовая страница некст.js. Теперь вы можете гордо сказать, что развернули Next.js-приложение, хотя пока всё, что вы сделали — это запустили команду и нажали Enter несколько раз. Впрочем, современная веб-разработка в целом к этому и сводится — большую часть времени мы просто настраиваем инструменты вместо написания кода. Кажется, так и было задумано.
Теперь вы готовы изменить мир — или, по крайней мере, содержимое файла pages/index.js (или app/page.js, если вы выбрали новый App Router). Из этой заготовки вы можете создать что угодно — от простого блога до полнофункционального клона Amazon. Ну, теоретически.
Основы работы
Структура страниц
В Next.js структура папок и файлов — это не просто способ поддерживать порядок, это практически религия. Представьте, что ваша файловая система — это одновременно и карта сайта, и роутер, и документация вашего проекта. Удивительно, но это работает намного лучше, чем звучит.
В мире некст.js существует два подхода к организации страниц — старый добрый pages и новомодный app (появившийся в Next.js 13). Они могут жить вместе, хотя это похоже на размещение в одной квартире бабушки, которая любит смотреть сериалы по телевизору, и внука-подростка, играющего в Call of Duty на полной громкости — теоретически возможно, но конфликты неизбежны.
Директория pages работает удивительно просто:
- Создали файл pages/about.js — получили страницу /about.
- Создали pages/blog/post.js — появился URL /blog/post.
- Положили файл pages/contact/index.js — доступен по /contact.
Директория app — более новый подход, который работает похоже, но с дополнительными фишками:
- Страницы определяются файлами page.js внутри вложенных папок.
- Каждая папка представляет сегмент URL.
- Можно добавлять файлы layout.js для общих шаблонов.
- Куча специальных файлов вроде loading.js, error.js, которые автоматически используются в нужных ситуациях.
Например, чтобы создать страницу /dashboard/settings, вам нужно создать структуру app/dashboard/settings/page.js. Выглядит чуть более многословно, но зато какие возможности для вложенных макетов!
Если оба подхода используются одновременно, то app имеет приоритет — примерно как в семье, где младший ребенок почему-то всегда получает то, что хочет.
Типы рендеринга
Next.js предлагает несколько способов рендеринга страниц, как в ресторане со слишком большим меню. Выбор правильного подхода может значительно повлиять на производительность — так же, как выбор между такси и общественным транспортом в час пик.

Диаграмма иллюстрирует, что в Next.js не существует универсального подхода к рендерингу страниц — каждый метод (SSR, SSG, ISR, CSR) применяется в зависимости от задач. Например, статическая генерация (SSG) особенно популярна на лендингах и в блогах, тогда как SSR чаще используется в административных панелях или страницах с персонализацией. Диаграмма помогает быстро уловить баланс между подходами и выбрать оптимальный метод рендеринга под конкретный случай.
SSR (Server-Side Rendering) — HTML генерируется на сервере для каждого запроса. Это как персональный повар, который готовит блюдо по заказу — свежо, но требует времени и ресурсов. Идеально для страниц с часто меняющимися данными или персонализированным контентом. Реализуется через getServerSideProps в Pages Router или через серверные компоненты в App Router.
// В Pages Router export async function getServerSideProps() { const data = await fetch('https://api.example.com/data'); return { props: { data } } }
SSG (Static Site Generation) — HTML генерируется заранее, при сборке проекта. Это как заморозка готовых блюд — быстро подаётся, но не всегда свежее. Отлично подходит для блогов, документации, лендингов — страниц, которые не меняются часто. Используйте getStaticProps для этого.
// В Pages Router export async function getStaticProps() { const data = await fetch('https://api.example.com/data'); return { props: { data } } }
ISR (Incremental Static Regeneration) — гибрид SSG и SSR, где статические страницы могут периодически обновляться. Это как ресторан, который обновляет свежеприготовленную пищу каждые несколько часов. Идеально для контента, который меняется, но не постоянно.
export async function getStaticProps() { return { props: { data }, revalidate: 3600 // Обновлять раз в час } }
CSR (Client-Side Rendering) — рендеринг происходит в браузере пользователя. Это как доставка ингредиентов клиенту, чтобы он сам готовил — экономит ресурсы сервера, но клиент может быть не в восторге. Используйте это для приватных, защищённых паролем страниц или интерактивных дашбордов.
import { useEffect, useState } from 'react' function Dashboard() { const [data, setData] = useState(null) useEffect(() => { // Загрузка данных на клиенте fetch('/api/dashboard-data') .then(res => res.json()) .then(setData) }, []) if (!data) return
Загружаем данные… или притворяемся, что загружаем
return
}
Выбор правильного типа рендеринга похож на выбор между электромобилем и дизельным грузовиком — всё зависит от ваших конкретных задач, бюджета и готовности идти на компромиссы. И да, в одном приложении можно использовать разные типы рендеринга для разных страниц — он достаточно гибок, чтобы не загонять вас в угол, где приходится выбирать между производительностью и удобством разработки.
Работа с данными в Next.js
Методы получения данных
Работа с данными в некст.js — это как шведский стол в отеле «всё включено». Есть множество вариантов, и все они хороши по-своему (и да, здесь невозможно не переесть API). Фреймворк предлагает ряд функций, которые позволяют получать данные на разных этапах жизненного цикла приложения — примерно как разные способы достать деньги из банкомата: кто-то снимает всю зарплату в первый день, а кто-то растягивает на месяц.

Столбчатая диаграмма сравнивает три популярных метода получения данных в Next.js — getStaticProps, getServerSideProps, useSWR — по двум критериям: скорость и гибкость. Значения от 1 до 10 выставлены условно на основе их поведения на практике.
getStaticProps — пожалуй, самая любимая функция среди NextJS-разработчиков. Она работает во время сборки и позволяет получить данные, которые будут «запечены» в статические страницы.
// pages/posts.js export async function getStaticProps() { // Здесь можно делать абсолютно любые асинхронные операции const res = await fetch('https://api.example.com/posts') const posts = await res.json() // Обязательно возвращаем объект с props внутри return { props: { posts, // Эти данные будут доступны компоненту как props generatedAt: new Date().toISOString(), // Можно добавить любые данные }, // Пересоздавать страницу каждые 10 минут (ISR) revalidate: 600 } } // Основной компонент страницы получает данные как props export default function Posts({ posts, generatedAt }) { return (
Данные получены: {generatedAt} {posts.map(post =>{post.title} )} ) }
getServerSideProps — функция, выполняющаяся на каждый запрос к странице. Примерно как бариста, готовящий кофе для каждого нового клиента — свежий, но иногда приходится подождать.
// pages/dashboard.js export async function getServerSideProps(context) { // context содержит параметры запроса, cookies и прочие полезности const { req, params, query } = context // Можно использовать cookies для авторизации const cookies = req.headers.cookie // Получаем данные для конкретного пользователя const res = await fetch('https://api.example.com/dashboard', { headers: { Cookie: cookies } }) const dashboardData = await res.json() return { props: { dashboardData } } }
getStaticPaths — функция-компаньон для getStaticProps в случае динамических страниц. Сообщает Next.js, какие конкретно страницы нужно предварительно сгенерировать.
// pages/posts/[id].js export async function getStaticPaths() { // Получаем список всех доступных постов const res = await fetch('https://api.example.com/posts') const posts = await res.json() // Формируем пути для каждого поста const paths = posts.map(post => ({ params: { id: post.id.toString() } })) return { paths, // Если страница не предгенерирована: // false - 404 ошибка // true - генерируем на лету при запросе // 'blocking' - SSR без мигающего loading state fallback: 'blocking' } } export async function getStaticProps({ params }) { // Получаем данные для конкретного поста const res = await fetch(`https://api.example.com/posts/${params.id}`) const post = await res.json() return { props: { post } } }
useSWR — хук для клиентской выборки данных с автоматической валидацией и кэшированием. Это как умные часы, которые сами проверяют ваш пульс, не дожидаясь команды.
import useSWR from 'swr' // Функция для получения данных const fetcher = url => fetch(url).then(r => r.json()) function Profile() { // Данные автоматически кэшируются и обновляются const { data, error, isLoading } = useSWR('/api/user', fetcher) if (error) return
if (isLoading) return
return
}
Метод | Когда выполняется | Кэширование | Используется для | Недостатки |
---|---|---|---|---|
getStaticProps | При сборке | Да | Контент, который редко меняется | Данные могут устареть |
getServerSideProps | На каждый запрос | Нет | Персонализированный, постоянно меняющийся контент | Медленнее, нагружает сервер |
getStaticPaths | При сборке | Н/П | Определение динамических страниц для предгенерации | Нужно знать все пути заранее |
useSWR | На клиенте | Да | Часто обновляемые данные, требующие интерактивности | Требует JS на клиенте |
Когда использовать тот или иной метод?
Выбор правильного метода получения данных — это как выбор между такси, автобусом и личным автомобилем. Всё зависит от ваших потребностей, бюджета и склонности к страданиям.
Используйте getStaticProps, когда:
- Данные могут быть получены заранее.
- Страница одинакова для всех пользователей.
- SEO критически важен.
- Сайт имеет большой трафик, и вы хотите снизить нагрузку на сервер.
Пример: блоги, документация, каталог товаров с редкими обновлениями.
Используйте getServerSideProps, когда:
- Данные часто меняются.
- Страница должна показывать актуальные данные.
- Контент персонализирован для каждого пользователя.
- Страница требует доступа к cookies или заголовкам запроса.
Пример: панель администратора, страница профиля, персонализированные рекомендации.
Используйте useSWR (клиентский рендеринг), когда:
- Данные обновляются в реальном времени.
- Пользователь активно взаимодействует с данными.
- SEO не так важен для этой конкретной страницы.
- Вы хотите кэшировать данные между страницами.
Пример: чаты, уведомления, интерактивные дашборды, счетчики лайков.
В реальной жизни большинство проектов требуют комбинированного подхода — как шведский стол, где можно и суши попробовать, и пасту, и не пропустить десерт. Главный лайфхак: начинайте с самого простого (getStaticProps), а потом усложняйте, если действительно нужно. Иногда простое предварительное кэширование решает 90% проблем производительности без необходимости писать сложную логику клиентской валидации и обновления данных.
Маршрутизация и динамические страницы
Как работает маршрутизация
Маршрутизация в Next.js — это как идеальный брак между простотой и мощью. В отличие от React Router, где вам нужно явно определять каждый маршрут (примерно как расписывать поминутный план дня для подростка), некст.js использует файловую систему как основу для маршрутизации — буквально «что видишь, то и получаешь».
Основной принцип прост до безобразия: каждый файл в директории pages (или app для новой версии роутера) становится маршрутом. Это работает настолько интуитивно, что даже далекий от программирования контент-менеджер может понять, где нужно править файлы для конкретных страниц.
pages/ ├── index.js // -> / ├── about.js // -> /about ├── contact.js // -> /contact └── blog/ ├── index.js // -> /blog └── [slug].js // -> /blog/:slug (динамический параметр)
Навигация между страницами осуществляется через компонент Link, который под капотом использует клиентскую маршрутизацию с предзагрузкой — это как телепортация, только для веб-страниц.
import Link from 'next/link' export default function Navigation() { return (
) }
Для программной навигации есть хук useRouter — как навигатор в машине, только без раздражающего голоса, повторяющего «пересчитываю маршрут».
import { useRouter } from 'next/router' export default function LoginForm() { const router = useRouter() async function handleSubmit(e) { e.preventDefault() // Логика авторизации const success = await loginUser(/* ... */) if (success) { // Программное перенаправление router.push('/dashboard') } } return
}
Динамические маршруты
Динамические маршруты в Next.js — то, что делает фреймворк по-настоящему мощным. Представьте, что вам нужно создать тысячи страниц для товаров в интернет-магазине. В старые добрые времена пришлось бы либо генерировать тысячи статических HTML-файлов, либо писать кастомный роутер. В некст.js вы просто создаете файл с квадратными скобками в названии.
Например, файл pages/products/[id].js будет соответствовать любому URL вида /products/1, /products/fancy-shirt или даже /products/why-is-programming-so-complicated.
Чтобы получить значение параметра внутри компонента:
import { useRouter } from 'next/router' export default function Product() { const router = useRouter() const { id } = router.query return
}
Для сложных случаев Next.js поддерживает множественные параметры и даже catch-all маршруты:
pages/ ├── blog/ │ └── [slug].js // -> /blog/:slug ├── products/ │ └── [category]/[id].js // -> /products/:category/:id └── [...catchAll].js // -> Ловит все остальные маршруты
Когда вы используете статическую генерацию с динамическими маршрутами, вам нужно указать Next.js, какие именно страницы следует предварительно сгенерировать — это делается с помощью getStaticPaths:
// pages/posts/[id].js export async function getStaticPaths() { // Получаем список всех ID постов из API const posts = await fetchPosts() // Формируем массив путей для предгенерации const paths = posts.map(post => ({ params: { id: post.id.toString() } })) return { paths, // 'blocking' означает "если страница не предгенерирована, // сгенерируй её на сервере при первом запросе" fallback: 'blocking' } }
API-роуты
API-роуты — это как мини-бэкенд внутри вашего фронтенд-приложения. Они позволяют создавать серверные эндпоинты прямо в Next.js проекте без необходимости поднимать отдельный сервер. Файлы в директории pages/api становятся эндпоинтами, доступными по URL /api/*.
Базовый API-роут выглядит так:
// pages/api/hello.js export default function handler(req, res) { // req -- стандартный объект запроса Node.js // res -- стандартный объект ответа Node.js res.status(200).json({ message: 'Hello, API world!' }) }
API-роуты могут быть динамическими, точно так же, как обычные страницы:
// pages/api/users/[id].js export default function handler(req, res) { const { id } = req.query const { method } = req switch (method) { case 'GET': // Получение пользователя res.status(200).json({ id, name: 'Джон Доу' }) break case 'PUT': // Обновление пользователя res.status(200).json({ id, name: req.body.name }) break default: res.setHeader('Allow', ['GET', 'PUT']) res.status(405).end(`Метод ${method} не поддерживается`) } }
Что круто в API-роутах:
- Они выполняются только на сервере, поэтому вы можете безопасно хранить там секреты API
- Они изолированы от клиентского кода — ваши токены и пароли не попадут в клиентский бандл
- Они следуют той же логике маршрутизации, что и обычные страницы — никаких дополнительных настроек
API-роуты часто используются для:
- Обработки форм.
- Взаимодействия с базами данных.
- Прокси-запросов к внешним API (особенно когда нужно скрыть ключи API).
- Аутентификации и авторизации.
- Обработки вебхуков от сторонних сервисов.
// pages/api/subscribe.js import { addSubscriber } from '../../lib/mailchimp' export default async function handler(req, res) { if (req.method !== 'POST') { return res.status(405).end() } try { const { email } = req.body // Здесь можно использовать приватные API-ключи await addSubscriber(email, process.env.MAILCHIMP_API_KEY) res.status(200).json({ success: true }) } catch (error) { res.status(500).json({ error: error.message }) } }
В сущности, API-роуты позволяют создавать полноценные fullstack-приложения в рамках одного проекта, что в разы упрощает разработку небольших и средних проектов. Но помните — это не замена полноценному бэкенду для крупных приложений, а скорее удобный инструмент для прототипирования и создания функциональных MVP.
Работа с макетами (layouts) и общими компонентами
Макеты в некст.js — это как архитектурный шаблон дома, где меняется только внутренняя начинка, а фундамент, стены и крыша остаются неизменными. Они позволяют избежать дублирования кода и поддерживать целостный вид приложения — что особенно актуально, когда ваш проект растет из маленького MVP в многостраничного монстра с десятками разделов.
Next.js предлагает несколько способов реализации макетов, и выбор подхода зависит от того, используете ли вы Pages Router или App Router. Поговорим о каждом из них — с их преимуществами и «внезапными особенностями» (это программистский эвфемизм для «багов, которые мы переименовали в фичи»).
Глобальные настройки с _app.js и _document.js
Файл _app.js — это корень вашего приложения, место, где можно настроить общее поведение для всех страниц. Это как мозговой центр вашего Next.js проекта, через который проходит каждый запрос.
// pages/_app.js import '../styles/globals.css' // Глобальные стили import Header from '../components/Header' import Footer from '../components/Footer' function MyApp({ Component, pageProps }) { // Component -- текущая страница // pageProps -- пропсы, которые получает страница от getServerSideProps/getStaticProps return ( <>
</> ) } export default MyApp
Этот подход позволяет применить общий макет ко всем страницам сразу. Но что если у вас есть несколько разных макетов? Например, один для публичных страниц, другой для админки, третий для блога? Здесь на помощь приходит паттерн с использованием свойства getLayout.
// components/layouts/AdminLayout.js export default function AdminLayout({ children }) { return (
) } // pages/admin/dashboard.js import AdminLayout from '../../components/layouts/AdminLayout' function Dashboard() { return
} // Определяем метод getLayout для страницы Dashboard.getLayout = page => {page} export default Dashboard // pages/_app.js (поддержка getLayout) function MyApp({ Component, pageProps }) { // Используем getLayout, если определен, иначе рендерим страницу как есть const getLayout = Component.getLayout || (page => page) return getLayout() }
Если вам нужно управлять HTML-документом целиком (например, добавить атрибуты к тегу <html> или настроить <head>), можно использовать _document.js:
// pages/_document.js import { Html, Head, Main, NextScript } from 'next/document' export default function MyDocument() { return (
{/* Здесь рендерится приложение */} {/* Скрипты Next.js */} {/* Можно добавить дополнительные скрипты в конец body */} ) }
Вложенные макеты в App Router
В новом App Router макеты реализованы на уровне файловой системы, что делает структуру приложения более наглядной, но может приводить к некоторой перегруженности директорий.
app/ ├── layout.js // Корневой макет для всего приложения ├── page.js // Главная страница (/) ├── about/ │ └── page.js // Страница /about └── dashboard/ ├── layout.js // Макет для всего раздела dashboard ├── page.js // Страница /dashboard └── settings/ └── page.js // Страница /dashboard/settings
Макеты в App Router автоматически вкладываются друг в друга:
// app/layout.js (корневой макет) export default function RootLayout({ children }) { return (
{children}
) } // app/dashboard/layout.js (макет для раздела dashboard) export default function DashboardLayout({ children }) { return (
) }
Преимущество этого подхода в том, что при переходе между страницами внутри одного макета только содержимое страницы обновляется, а макет остается неизменным — без перерендера. Это приводит к более плавным переходам и сохранению состояния компонентов макета (например, активного пункта меню или открытого модального окна).
Группировка маршрутов без влияния на URL
Иногда нужно сгруппировать маршруты для организации кода, но не отражать эту группировку в URL. В App Router для этого используются папки в скобках:
app/ ├── (marketing)/ │ ├── layout.js // Макет для маркетинговых страниц │ ├── page.js // Главная (/) │ └── about/ │ └── page.js // /about └── (shop)/ ├── layout.js // Макет для магазина ├── products/ │ └── page.js // /products └── cart/ └── page.js // /cart
Это позволяет разделить код приложения на логические группы с разными макетами, не усложняя URL для конечных пользователей.
Макеты — это не просто инструмент для избавления от дублирования кода. Они помогают создавать связный пользовательский опыт и улучшают производительность приложения. Правильно структурированные макеты также упрощают поддержку приложения в долгосрочной перспективе — когда вам нужно изменить шапку на всех страницах, вы меняете её в одном месте, а не в десятках файлов по всему проекту.
Вместе с компонентами Link для клиентской навигации и useRouter для императивной навигации, макеты создают полноценную систему, которая позволяет создавать сложные, многостраничные приложения с удобной структурой и оптимальной производительностью. И да, без необходимости настраивать webpack для каждого нового проекта — что уже само по себе стоит многого.
Оптимизация производительности и SEO в Next.js
Улучшение загрузки страниц
Производительность веб-приложений — это как здоровое питание: все знают, что это важно, но мало кто действительно уделяет этому должное внимание, пока не появятся проблемы. В случае с сайтами «проблемы» — это отскок пользователей, которые не хотят ждать три секунды, пока загрузится ваша мегаоптимизированная карусель продуктов с 500 JavaScript-зависимостями.
К счастью, Next.js изначально заточен под производительность и предлагает ряд инструментов, которые делают вашу жизнь (и жизнь ваших пользователей) значительно легче.
Разделение кода (code-splitting)
Next.js автоматически разбивает ваш код на маленькие кусочки, чтобы пользователю не приходилось загружать весь сайт целиком только для просмотра одной страницы. Это как доставка продуктов по запросу вместо закупки на месяц вперед — получаете только то, что нужно прямо сейчас.
// Код загружается автоматически только при необходимости import dynamic from 'next/dynamic' // Компонент загрузится только когда понадобится const DynamicComponent = dynamic(() => import('../components/HeavyComponent')) export default function Page() { const [showComponent, setShowComponent] = useState(false) return (
) }
Ленивая загрузка компонентов
Для больших компонентов, которые не являются критически важными для первого рендера, можно использовать динамический импорт с ленивой загрузкой:
// Стандартный импорт (загружается сразу) import RegularComponent from '../components/RegularComponent' // Динамический импорт (загружается только когда нужен) const HeavyChart = dynamic(() => import('../components/HeavyChart'), { // Показать запасной UI, пока компонент загружается loading: () =>
Загружаем график…
, // Не рендерить на сервере (полезно для библиотек, работающих только в браузере) ssr: false, }) export default function Dashboard() { return (
) }
Оптимизация изображений (next/image)
Изображения — одна из главных причин медленной загрузки сайтов. Компонент Image из Next.js решает эту проблему, автоматически оптимизируя картинки и применяя ленивую загрузку. Это как нанять персонального тренера для ваших JPEG-файлов — они сразу становятся стройнее и эффективнее.
import Image from 'next/image' import profilePic from '../public/profile.jpg' function Profile() { return (
) }
Префетчинг страниц
Next.js автоматически предзагружает страницы, на которые, вероятно, перейдет пользователь. Это как предугадывать, какой кофе захочет ваш клиент, и начинать его готовить заранее.
// Link автоматически предзагружает страницы в поле видимости import Link from 'next/link' export default function Navigation() { return (
) }
Как Next.js улучшает SEO?
SEO в современных JavaScript-приложениях — это как фитнес для людей с сидячей работой: необходимо, но часто игнорируется. Next.js решает многие проблемы SEO прямо из коробки, делая ваш сайт более дружественным к поисковым роботам.
SSR и SSG для поисковой оптимизации
Самое большое преимущество Next.js для SEO — это серверный рендеринг и статическая генерация. Поисковые боты получают полностью сформированный HTML вместо пустой страницы с кучей JavaScript, который нужно интерпретировать. Это как разница между получением готового отчета и сырых данных, которые еще нужно обработать.
// pages/blog/[slug].js export async function getStaticProps({ params }) { const post = await getPostBySlug(params.slug) return { props: { post, // Данные для структурированной разметки structuredData: { '@context': 'https://schema.org', '@type': 'BlogPosting', 'headline': post.title, 'datePublished': post.date, 'author': { '@type': 'Person', 'name': post.author.name } } } } } export async function getStaticPaths() { const posts = await getAllPosts() return { paths: posts.map(post => ({ params: { slug: post.slug } })), fallback: 'blocking' // Для новых постов генерируем HTML на сервере } }
Управление метатегами через next/head
Компонент Head позволяет динамически изменять метатеги, заголовки и другие элементы <head>. Это как иметь возможность менять обложку книги в зависимости от того, кто её читает.
import Head from 'next/head' function ProductPage({ product }) { return ( <> {/* Структурированные данные для расширенных результатов в поиске */}
Sitemap и robots.txt
Для крупных сайтов важно иметь карту сайта и правильно настроенный robots.txt. Next.js позволяет генерировать их динамически:
// pages/sitemap.xml.js export async function getServerSideProps({ res }) { const pages = await getAllPages() // Генерируем XML const sitemap = ` ${pages.map(page => ` ${`https://example.com/${page.slug}`} ${page.updatedAt} `).join('')} ` res.setHeader('Content-Type', 'text/xml') res.write(sitemap) res.end() return { props: {}, } } export default function Sitemap() { // Эта страница никогда не рендерится, мы возвращаем XML в getServerSideProps return null } // pages/robots.txt.js export async function getServerSideProps({ res }) { res.setHeader('Content-Type', 'text/plain') res.write(`User-agent: * Allow: / Disallow: /admin/ Sitemap: https://example.com/sitemap.xml`) res.end() return { props: {}, } } export default function Robots() { return null }
Работа со стилями в Next.js
Способы подключения CSS и препроцессоров
Работа со стилями в веб-разработке — это примерно как мода: тренды постоянно меняются, но базовые принципы остаются теми же. Next.js понимает эту динамику и предлагает гибкую систему для работы со стилями, которая удовлетворит и хипстера с его CSS-in-JS, и консерватора, предпочитающего обычный CSS.
Глобальные стили (globals.css)
Самый простой способ добавить стили в Next.js — использовать глобальный CSS. Это как покрасить все стены в доме одним цветом — быстро, эффективно, но без особого изящества.
// pages/_app.js import '../styles/globals.css' function MyApp({ Component, pageProps }) { return } export default MyApp
В globals.css можно определить базовые стили для всего приложения:
/* styles/globals.css */ :root { --primary-color: #0070f3; --text-color: #333; } body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; color: var(--text-color); margin: 0; padding: 0; } a { color: var(--primary-color); text-decoration: none; } /* и так далее... */
Важно: глобальные стили можно импортировать только в _app.js — Next.js на это очень обидчив.
Модули CSS (styles.module.css)
Для компонентного подхода Next.js предлагает CSS модули. Это как иметь отдельную банку краски для каждой комнаты — цвета не смешиваются, и вы точно знаете, что покрасили именно ту стену, которую хотели.
/* components/Button.module.css */ .button { padding: 0.5rem 1rem; background: var(--primary-color); color: white; border: none; border-radius: 4px; cursor: pointer; } .danger { background: #ff4136; }
// components/Button.js import styles from './Button.module.css' export default function Button({ children, danger }) { return ( <button className={`${styles.button} ${danger ? styles.danger : ''}`}> {children} </button> ) }
CSS модули автоматически генерируют уникальные имена классов при сборке, поэтому вы никогда не столкнетесь с конфликтами имен — что-то вроде .Button_button__x5fGp. Это как иметь личного телохранителя для каждого CSS класса, оберегающего его от столкновений.
Поддержка Sass
Если вы фанат препроцессоров (и кто вас осудит — писать вложенные селекторы в чистом CSS это примерно как есть суп вилкой), Next.js поддерживает Sass из коробки:
npm install sass
После установки вы можете использовать .scss или .sass файлы как обычные CSS:
// styles/Home.module.scss .container { padding: 2rem; .title { font-size: 2rem; margin-bottom: 1rem; &:hover { color: var(--primary-color); } } @media (max-width: 768px) { padding: 1rem; } }
import styles from '../styles/Home.module.scss' export default function Home() { return ( <div className={styles.container}> <p>Привет, мир!</p> </div> ) }
Использование styled-components и Tailwind CSS
Если вы предпочитаете более современные подходы к стилизации, Next.js отлично работает с популярными CSS-in-JS библиотеками и утилитарными фреймворками.
Styled Components
Для работы с Styled Components в Next.js нужно немного дополнительной настройки, но результат стоит затраченных усилий:
npm install styled-components
Чтобы избежать проблем с SSR, нужно настроить _document.js:
// pages/_document.js import Document, { Html, Head, Main, NextScript } from 'next/document' import { ServerStyleSheet } from 'styled-components' export default class MyDocument extends Document { static async getInitialProps(ctx) { const sheet = new ServerStyleSheet() const originalRenderPage = ctx.renderPage try { ctx.renderPage = () => originalRenderPage({ enhanceApp: (App) => (props) => sheet.collectStyles(), }) const initialProps = await Document.getInitialProps(ctx) return { ...initialProps, styles: ( <> {initialProps.styles} {sheet.getStyleElement()} </> ), } } finally { sheet.seal() } } }
После настройки вы можете использовать всю мощь Styled Components:
import styled from 'styled-components' const StyledButton = styled.button` padding: 0.5rem 1rem; background: ${props => props.danger ? '#ff4136' : '#0070f3'}; color: white; border: none; border-radius: 4px; cursor: pointer; &:hover { opacity: 0.8; } ` export default function Button({ children, danger }) { return {children} }
Tailwind CSS
Если вы принадлежите к культу Tailwind (и я не осуждаю — писать CSS классами прямо в HTML настолько удобно, что почти незаконно), Next.js сделает вас счастливым:
npm install tailwindcss postcss autoprefixer npx tailwindcss init -p
Настройте tailwind.config.js:
// tailwind.config.js module.exports = { content: [ './pages/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}', './app/**/*.{js,ts,jsx,tsx}', ], theme: { extend: { colors: { brand: '#0070f3', }, }, }, plugins: [], }
Добавьте директивы Tailwind в ваш глобальный CSS:
/* styles/globals.css */ @tailwind base; @tailwind components; @tailwind utilities; @layer components { .btn { @apply py-2 px-4 rounded; } .btn-primary { @apply bg-brand text-white; } }
И теперь вы можете использовать Tailwind в ваших компонентах:
export default function Card({ title, description }) { return (
{title}
{description}
) }
Деплой и развертывание Next.js-приложений
Как развернуть проект на Vercel?
Когда дело доходит до деплоя Next.js-приложений, Vercel — это что-то вроде родного дома для вашего кода. Неудивительно, ведь команда Vercel и создала Next.js, так что они как родители, которые точно знают, как правильно кормить и воспитывать своего ребенка. И, честно говоря, процесс деплоя на Vercel настолько прост, что иногда кажется подозрительным — как будто вам предлагают конфету в темном переулке (но в данном случае конфета действительно вкусная и безопасная).
- Скриншот с сайта Vercel.com
Вот пошаговая инструкция, которую осилит даже разработчик, не спавший 48 часов перед дедлайном:
1. Создайте аккаунт на Vercel Зайдите на vercel.com и зарегистрируйтесь (удобнее всего через GitHub).
2. Подключите репозиторий
- Нажмите «Import Project».
- Выберите «Import Git Repository».
- Выберите свой репозиторий из GitHub/GitLab/Bitbucket.
3. Настройте проект
- Vercel автоматически определит, что это Next.js-проект.
- При необходимости добавьте переменные окружения в соответствующем разделе.
- Настройте команду сборки, если используете что-то нестандартное.
4. Нажмите «Deploy»
Теперь можно пойти сделать кофе, но обычно не успеете — Vercel разворачивает проекты быстрее, чем вы наливаете воду в чашку.
5. Наслаждайтесь результатом
- Получите URL вашего развернутого приложения.
- Каждый новый пуш в мастер будет автоматически деплоиться.
- Для каждого pull request создается отдельный preview-деплой.
Деплой на других платформах
Хотя Vercel — это идеальная платформа для Next.js, иногда корпоративная политика, бюджетные ограничения или личные предпочтения заставляют искать альтернативы. К счастью, Next.js достаточно гибок, чтобы работать практически везде, где есть Node.js.
AWS (Amazon Web Services)
- Скриншот с сайта AWS
AWS — это как швейцарский армейский нож для девопсов: тысячи возможностей, но иногда сложно найти нужную открывашку. Для деплоя Next.js можно использовать несколько подходов:
- AWS Amplify — самый простой путь, похожий на Vercel.
- Elastic Beanstalk — для тех, кто предпочитает более традиционный подход.
- EC2 + CloudFront — для полного контроля и максимальной гибкости.
Базовый процесс для Amplify:
# Установите AWS Amplify CLI npm install -g @aws-amplify/cli amplify configure # Инициализируйте проект amplify init # Добавьте хостинг amplify add hosting # Опубликуйте amplify publish
DigitalOcean
DigitalOcean — это как уютная квартира в хорошем районе: не так много места, как в особняке AWS, но всё на своих местах и цены разумные.
- Создайте новый дроплет (или используйте App Platform).
- Установите Node.js и настройте Nginx как прокси.
- Клонируйте ваш репозиторий.
- Запустите сборку и PM2 для управления процессом:
npm install npm run build npm install -g pm2 pm2 start npm --name "next" -- start
Netlify
Netlify — это как соседняя деревня рядом с городом Vercel: очень похожая атмосфера, но со своими особенностями.
- Зарегистрируйтесь на Netlify.
- Подключите репозиторий.
- Добавьте netlify.toml в корень проекта:
[build] command = "npm run build" publish = ".next" [[plugins]] package = "@netlify/plugin-nextjs"
- Установите плагин Next.js:
npm install -D @netlify/plugin-nextjs
- Нажмите «Deploy» в интерфейсе Netlify.
Heroku
Heroku — это как старый друг: не самый модный, но надежный и проверенный временем.
1. Установите Heroku CLI и создайте приложение:
heroku create my-nextjs-app
2. Добавьте Procfile в корень проекта:
web: npm start
3. Настройте скрипты в package.json:
"scripts": { "dev": "next dev", "build": "next build", "start": "next start -p $PORT" }
4. Деплой:
git push heroku master
Docker + Next.js: как контейнеризировать приложение
Docker — это как перевозка мебели в контейнере: упаковали всё необходимое, и можно быть уверенным, что на новом месте всё будет работать точно так же. Для Next.js-приложений Docker особенно удобен, когда нужна переносимость и изоляция.
- Скриншот с сайта Docker
Вот базовый Dockerfile для Next.js-приложения:
# Базовый образ FROM node:18-alpine AS base # Шаг установки зависимостей FROM base AS deps WORKDIR /app COPY package.json package-lock.json ./ RUN npm ci # Шаг сборки FROM base AS builder WORKDIR /app COPY --from=deps /app/node_modules ./node_modules COPY . . RUN npm run build # Шаг запуска приложения FROM base AS runner WORKDIR /app ENV NODE_ENV production # Копируем только нужные файлы COPY --from=builder /app/public ./public COPY --from=builder /app/.next ./.next COPY --from=builder /app/node_modules ./node_modules COPY --from=builder /app/package.json ./package.json # Запускаем приложение EXPOSE 3000 CMD ["npm", "start"]
Для более продвинутых сценариев можно использовать multi-stage build для оптимизации размера образа и ускорения сборки. Также стоит рассмотреть Docker Compose для управления несколькими сервисами, особенно если ваше приложение использует базу данных или другие зависимости.
# docker-compose.yml version: '3' services: nextjs: build: . ports: - "3000:3000" environment: - DATABASE_URL=postgres://user:password@postgres:5432/mydb postgres: image: postgres:14 environment: - POSTGRES_USER=user - POSTGRES_PASSWORD=password - POSTGRES_DB=mydb volumes: - postgres-data:/var/lib/postgresql/data volumes: postgres-data:
Выбор платформы для деплоя Next.js в итоге зависит от ваших конкретных требований, бюджета и личных предпочтений. Как и в большинстве технических решений, здесь нет единственного правильного ответа — есть компромиссы, которые стоит оценить:
- Vercel: минимальные усилия, максимальная совместимость, но ограниченный контроль.
- AWS: максимальный контроль и масштабируемость, но требует больше настройки.
- Netlify/Heroku: золотая середина между простотой и функциональностью.
- Docker: отличный вариант для непрерывной интеграции и развертывания (CI/CD).
Заключение
Next.js — это как высококлассный швейцарский нож для современного веб-разработчика: можно долго спорить о том, нужны ли все эти функции, но когда они вам действительно потребуются, вы будете благодарны, что они у вас под рукой. Фреймворк блестяще справляется с рядом задач, которые раньше заставляли фронтенд-разработчиков седеть раньше времени.
Подводя итоги, можно сказать, что Next.js особенно хорош в следующих сценариях:
- Проекты с высокими требованиями к SEO — благодаря серверному рендерингу и статической генерации, поисковые системы видят полноценный HTML, а не пустую страницу с JavaScript.
- Высоконагруженные сайты — статически сгенерированные страницы можно раздавать через CDN, что значительно снижает нагрузку на сервер и улучшает время отклика.
- Корпоративные приложения — встроенная маршрутизация, API-роуты и разделение кода делают разработку больших проектов более структурированной и поддерживаемой.
- Гибридные проекты — сочетание различных типов рендеринга (SSG, SSR, CSR) в рамках одного приложения позволяет оптимизировать каждую страницу по-своему.
- Мультипользовательские платформы — возможность создавать защищенные маршруты и серверные API прямо в проекте упрощает разработку сложных систем аутентификации и авторизации.
Хотите попробовать себя в востребованной IT-профессии? Изучите курсы JavaScript разработчика. На них не только расскажут теорию, но и дадут практическую часть. Начните изучать новую профессию уже сегодня!
Рекомендуем посмотреть курсы по JavaScript разработке
Курс | Школа | Цена | Рассрочка | Длительность | Дата начала | Ссылка на курс |
---|---|---|---|---|---|---|
Автоматизированное тестирование веб-приложений на JavaScript
|
Skillbox
149 отзывов
|
Цена
Ещё -47% по промокоду
48 408 ₽
64 548 ₽
|
От
4 034 ₽/мес
Без переплат на 1 год.
5 379 ₽/мес
|
Длительность
4 месяца
|
Старт
31 августа
|
Ссылка на курс |
Полный курс по JavaScript — С нуля до результата!
|
Stepik
33 отзыва
|
Цена
2 990 ₽
|
От
748 ₽/мес
|
Длительность
1 неделя
|
Старт
в любое время
|
Ссылка на курс |
Fullstack-разработчик на JavaScript
|
Eduson Academy
68 отзывов
|
Цена
Ещё -5% по промокоду
143 800 ₽
|
От
11 983 ₽/мес
0% на 24 месяца
|
Длительность
9 месяцев
|
Старт
в любое время
|
Ссылка на курс |
Онлайн-курс JavaScript-разработчик
|
Бруноям
20 отзывов
|
Цена
Ещё -15% по промокоду
39 900 ₽
|
|
Длительность
4 месяца
|
Старт
22 сентября
Оговаривается индивидуально
|
Ссылка на курс |
Профессия: frontend-разработчик
|
ProductStar
38 отзывов
|
Цена
Ещё -16% по промокоду
129 600 ₽
288 000 ₽
|
От
5 233 ₽/мес
Рассрочка на 2 года.
11 600 ₽/мес
|
Длительность
10 месяцев
|
Старт
28 августа
|
Ссылка на курс |

Психотерапия – решение проблем или мода? Разбираемся в деталях
Психотерапия – это инструмент, который помогает разобраться в себе и улучшить качество жизни. В чем ее суть и как выбрать подходящий метод?

Прыгнула кнопка — улучшился интерфейс? Не всегда так просто
Что общего между магией и анимацией в iOS? Главное — эффект. В этом материале разберёмся, зачем нужны анимации, какие инструменты использовать и как не переборщить.

CRM-системы: зачем они нужны и как работают?
Что такое CRM-система и почему ее внедрение меняет подход к клиентскому сервису и продажам? Разбираем функции, виды и ключевые преимущества.

Как жизненный цикл ПО влияет на успех разработки
Что такое SDLC и как выбрать методологию для вашего проекта? В статье вы найдете практическое руководство, ключевые этапы и важные советы.