Next.js за 1 день: от нуля до деплоя
Create app, роутинг, серверные и клиентские компоненты, Tailwind CSS, деплой на Vercel — полный практический гайд.
Почему Next.js
Next.js — это React-фреймворк номер один в мире. Его используют Vercel, Netflix, TikTok, Twitch, Hulu и тысячи стартапов. В 2026 году это стандарт де-факто для веб-разработки.
Что даёт Next.js поверх React:
- Серверный рендеринг (SSR) — страницы быстро загружаются и индексируются поисковиками
- Файловый роутинг — создал файл = создал страницу
- API Routes — бэкенд прямо в проекте
- Server Components — компоненты работают на сервере (меньше JS на клиенте)
- Image Optimization — автоматическая оптимизация картинок
- Деплой в 1 клик на Vercel
К концу этой статьи вы создадите полноценное приложение и задеплоите его.
Подготовка
Убедитесь, что установлен Node.js:
node --version # v20+ или v22+
npm --version # 10+
Если нет — скачайте с nodejs.org.
Создание проекта
npx create-next-app@latest my-app
На вопросы отвечайте:
- TypeScript? → Yes
- ESLint? → Yes
- Tailwind CSS? → Yes
- src/ directory? → Yes
- App Router? → Yes
- Import alias? → @/* (по умолчанию)
cd my-app
npm run dev
Откройте http://localhost:3000 — вы увидите стартовую страницу Next.js.
Структура проекта
my-app/
├── src/
│ └── app/
│ ├── layout.tsx # Корневой лейаут (шаблон)
│ ├── page.tsx # Главная страница (/)
│ ├── globals.css # Глобальные стили
│ ├── about/
│ │ └── page.tsx # Страница /about
│ └── api/
│ └── hello/
│ └── route.ts # API эндпоинт /api/hello
├── public/ # Статические файлы
├── tailwind.config.ts # Конфиг Tailwind
├── tsconfig.json
└── package.json
Главное правило: Каждая папка в app/ = маршрут. Файл page.tsx = страница.
Роутинг
Статические страницы
Создайте файл — получите страницу:
src/app/about/page.tsx → /about
src/app/blog/page.tsx → /blog
src/app/contact/page.tsx → /contact
// src/app/about/page.tsx
export default function AboutPage() {
return (
<div className="max-w-2xl mx-auto p-8">
<h1 className="text-3xl font-bold mb-4">О нас</h1>
<p className="text-gray-600">
Мы создаём продукты с помощью ИИ.
</p>
</div>
)
}
Динамические маршруты
Для страниц вроде /blog/my-article используйте квадратные скобки:
// src/app/blog/[slug]/page.tsx
interface Props {
params: Promise<{ slug: string }>
}
export default async function BlogPost({ params }: Props) {
const { slug } = await params
return (
<div className="max-w-2xl mx-auto p-8">
<h1 className="text-3xl font-bold">Статья: {slug}</h1>
</div>
)
}
Теперь /blog/hello, /blog/world, /blog/любой-текст — всё работает.
Вложенные лейауты
Лейаут — это обёртка, общая для всех страниц в папке:
// src/app/blog/layout.tsx
export default function BlogLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<div className="flex">
<aside className="w-64 p-4 border-r">
<nav>
<a href="/blog" className="block mb-2">Все статьи</a>
<a href="/blog/categories" className="block mb-2">Категории</a>
</nav>
</aside>
<main className="flex-1 p-8">{children}</main>
</div>
)
}
Все страницы внутри /blog/ будут иметь сайдбар.
Server Components vs Client Components
Это ключевая концепция Next.js 15.
Server Components (по умолчанию)
Каждый компонент по умолчанию — серверный. Он рендерится на сервере и отправляет готовый HTML клиенту. Никакого JavaScript на клиенте.
// Server Component (по умолчанию)
// Можно делать fetch, обращаться к БД, читать файлы
async function UserList() {
const users = await fetch('https://api.example.com/users')
const data = await users.json()
return (
<ul>
{data.map((user: any) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
)
}
Client Components
Когда нужна интерактивность (клики, формы, useState), добавьте "use client":
'use client'
import { useState } from 'react'
export function Counter() {
const [count, setCount] = useState(0)
return (
<button
onClick={() => setCount(count + 1)}
className="px-4 py-2 bg-blue-600 text-white rounded"
>
Нажатий: {count}
</button>
)
}
Правило: Используйте Server Components везде, где возможно. Client Components — только для интерактивности.
Tailwind CSS
Tailwind уже настроен в проекте. Стилизуйте прямо в className:
export default function Card() {
return (
<div className="bg-white rounded-2xl shadow-lg p-6
hover:shadow-xl transition-shadow duration-300
border border-gray-100">
<h2 className="text-xl font-bold text-gray-900 mb-2">
Заголовок карточки
</h2>
<p className="text-gray-600 leading-relaxed">
Описание карточки с полезным контентом.
</p>
<button className="mt-4 px-6 py-2 bg-gradient-to-r
from-purple-600 to-blue-600 text-white
rounded-lg font-medium
hover:from-purple-700 hover:to-blue-700
transition-all duration-200">
Подробнее
</button>
</div>
)
}
Полезные классы Tailwind:
| Класс | Описание |
|-------|----------|
| max-w-7xl mx-auto | Контейнер с центровкой |
| flex items-center gap-4 | Flexbox с центровкой |
| grid grid-cols-3 gap-6 | CSS Grid 3 колонки |
| text-lg font-semibold | Размер и жирность текста |
| bg-gradient-to-r from-X to-Y | Градиент |
| hover:scale-105 transition | Анимация при наведении |
| dark:bg-gray-900 | Тёмная тема |
API Routes
Бэкенд прямо в Next.js проекте:
// src/app/api/generate/route.ts
import { NextRequest, NextResponse } from 'next/server'
import Anthropic from '@anthropic-ai/sdk'
const anthropic = new Anthropic()
export async function POST(request: NextRequest) {
const { prompt } = await request.json()
const message = await anthropic.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 1024,
messages: [{ role: 'user', content: prompt }],
})
return NextResponse.json({
text: message.content[0].type === 'text'
? message.content[0].text
: '',
})
}
Вызов из клиентского компонента:
'use client'
import { useState } from 'react'
export function AIForm() {
const [result, setResult] = useState('')
const [loading, setLoading] = useState(false)
async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault()
setLoading(true)
const formData = new FormData(e.currentTarget)
const prompt = formData.get('prompt') as string
const res = await fetch('/api/generate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ prompt }),
})
const data = await res.json()
setResult(data.text)
setLoading(false)
}
return (
<form onSubmit={handleSubmit} className="space-y-4">
<textarea
name="prompt"
className="w-full p-3 border rounded-lg"
placeholder="Введите промпт..."
rows={3}
/>
<button
type="submit"
disabled={loading}
className="px-6 py-2 bg-blue-600 text-white rounded-lg
disabled:opacity-50"
>
{loading ? 'Генерация...' : 'Сгенерировать'}
</button>
{result && (
<div className="p-4 bg-gray-50 rounded-lg whitespace-pre-wrap">
{result}
</div>
)}
</form>
)
}
Собираем мини-проект: AI Landing Generator
Давайте создадим реальное приложение — генератор лендингов на базе ИИ.
Структура:
src/app/
├── layout.tsx # Навигация
├── page.tsx # Главная (форма)
├── result/
│ └── page.tsx # Результат генерации
└── api/
└── generate/
└── route.ts # API для генерации
Главная страница:
// src/app/page.tsx
import { AIForm } from '@/components/AIForm'
export default function Home() {
return (
<main className="min-h-screen bg-gradient-to-b
from-gray-900 to-gray-800">
<div className="max-w-3xl mx-auto px-4 py-20">
<h1 className="text-5xl font-bold text-white text-center mb-4">
AI Landing Generator
</h1>
<p className="text-xl text-gray-400 text-center mb-12">
Опишите ваш продукт — получите готовый лендинг за 30 секунд
</p>
<AIForm />
</div>
</main>
)
}
Навигация в layout:
// src/app/layout.tsx
import type { Metadata } from 'next'
import './globals.css'
export const metadata: Metadata = {
title: 'AI Landing Generator',
description: 'Генерируй лендинги с помощью ИИ',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="ru">
<body>
<nav className="bg-gray-900 border-b border-gray-800 px-6 py-4">
<div className="max-w-7xl mx-auto flex justify-between items-center">
<a href="/" className="text-xl font-bold text-white">
LandingAI
</a>
<div className="flex gap-6">
<a href="/" className="text-gray-300 hover:text-white">
Генератор
</a>
<a href="/about" className="text-gray-300 hover:text-white">
О проекте
</a>
</div>
</div>
</nav>
{children}
</body>
</html>
)
}
Деплой на Vercel
Через GitHub (рекомендуется):
- Создайте репозиторий на GitHub
- Запушьте код:
git init
git add .
git commit -m "Initial commit"
git remote add origin https://github.com/username/my-app.git
git push -u origin main
- Зайдите на vercel.com → New Project → Import from GitHub
- Выберите репозиторий → Deploy
- Через 1 минуту — ваше приложение на
my-app.vercel.app
Через CLI:
npm install -g vercel
vercel
Ответьте на вопросы → деплой за 30 секунд.
Environment Variables:
Если у вас есть API-ключи (Claude API, Stripe и т.д.):
- Vercel Dashboard → Project → Settings → Environment Variables
- Добавьте переменные (ANTHROPIC_API_KEY, DATABASE_URL и т.д.)
- Redeploy
Чек-лист после деплоя
- [ ] Все страницы открываются
- [ ] Формы работают
- [ ] API-routes отвечают
- [ ] Изображения загружаются
- [ ] Мета-теги корректные (title, description)
- [ ] Адаптивность на мобильных
- [ ] Performance в Lighthouse > 90
Что дальше
Вы освоили основы Next.js за 1 день. Вот что изучить дальше:
- Server Actions — формы без API routes
- Middleware — перехват запросов (авторизация, редиректы)
- Metadata API — динамические SEO-теги
- Parallel Routes — несколько страниц в одном лейауте
- Streaming — поэтапная загрузка контента
Ресурсы:
- nextjs.org/docs — официальная документация
- nextjs.org/learn — интерактивный курс
- Vercel YouTube — видеоуроки
Хочешь изучить это глубже? Смотри наш курс — за неделю ты будешь создавать полноценные SaaS-приложения на Next.js с ИИ.