Введение
Долгое время вход и регистрация в новом Laravel-проекте появлялись одним из трёх способов: командой php artisan ui bootstrap --auth из пакета laravel/ui, через Breeze или через Jetstream. Laravel 12, вышедший 24 февраля 2025 года, поменял этот порядок. На смену Breeze и Jetstream пришли стартовые наборы (starter kits) — готовые шаблоны приложения, по одному на стек: React, Vue и Livewire, а позднее и Svelte. Под капотом у всех Laravel Fortify, а нужный вариант выбирается прямо в установщике laravel new.
При этом старые пакеты никуда не делись. Breeze (v2.4.2) и Jetstream (v5.5.3) совместимы с Laravel 13, но развиваться перестали: им достаются только обновления совместимости, а новые проекты команда Laravel советует начинать со стартовых наборов. Жив и laravel/ui — версия 4.6.3 вышла в марте 2026 года и поддерживает Laravel 9–13. Ниже разобрано, как выбрать набор, что в нём лежит и где laravel/ui по-прежнему оправдан.
Сравнение наборов
Бэкенд у четырёх официальных наборов одинаковый: Fortify, общий набор маршрутов авторизации, двухфакторная аутентификация и страницы настроек профиля. Различаются они фронтендом — именно он и определяет выбор.
| Вариант | Стек | Рендеринг | Кому подходит | Сложность поддержки |
|---|---|---|---|---|
| React | Inertia 3, React 19, TypeScript, Tailwind 4, shadcn/ui | SPA через Inertia, SSR по желанию | Командам, которые уже пишут на React; сложным интерфейсам | Composer и npm одновременно, типы, сборка |
| Vue | Inertia 3, Vue 3 (Composition API), TypeScript, Tailwind, shadcn-vue | SPA через Inertia, SSR по желанию | Проектам, где фронтенд на Vue | Так же, как у React |
| Svelte | Inertia 3, Svelte 5, TypeScript, Tailwind, shadcn-svelte | SPA через Inertia, SSR по желанию | Тем, кто остановился на Svelte | Так же, как у React, но готовых компонентов меньше |
| Livewire | Livewire 4, Tailwind, Flux UI | Blade на сервере, реактивность через Livewire | PHP-разработчикам без отдельного фронтендера | JavaScript почти не нужен, всё в Blade и PHP |
laravel/ui |
Blade, Bootstrap 5, по желанию Vue 3 или React 18 | На сервере | Старым проектам на Bootstrap, учебным задачам | Контроллеры с трейтами, без Fortify и 2FA |
| Без набора | Laravel как есть | Любой | API, своя схема авторизации, собственный UI | Всё пишется с нуля |
Inertia даёт писать страницы на React, Vue или Svelte, не отказываясь от маршрутов и контроллеров Laravel: ни отдельного API, ни клиентского роутера заводить не придётся. Livewire приходит к тому же результату иначе — компоненты остаются на PHP и Blade, JavaScript-фреймворк не нужен.
Практическое правило простое. Когда фронтендера в команде нет, меньше всего хлопот с Livewire-набором. React, Vue или Svelte оправданы, если в интерфейсе много логики на клиенте или фронтенд уже живёт на одном из этих фреймворков — тогда не придётся переучиваться.
Установка стартового набора
Набор ставит установщик Laravel: он по очереди задаёт вопросы и сам загружает подходящий шаблон.
composer global require laravel/installer
laravel new shop
cd shop
npm install && npm run build
composer run dev # сервер разработки: http://localhost:8000
# те же ответы флагами — для CI и скриптов
laravel new shop --livewire --teams --pest --no-boost
# набор сообщества с Packagist
laravel new shop --using=vendor/starter-kit
В версии установщика 5.32 вопросы идут в таком порядке:
- «Do you want to use a starter kit?» — нужен ли стартовый набор вообще.
- Стек: React, Svelte, Vue или Livewire.
- Кто отвечает за авторизацию: встроенные средства Laravel или WorkOS.
- Для Livewire отдельно — однофайловые компоненты или классические (класс + шаблон).
- Нужны ли команды (Teams).
- Pest или PHPUnit для тестов и ставить ли Laravel Boost.
- Какие функции авторизации оставить: подтверждение email, регистрацию, 2FA, passkeys, подтверждение пароля.
Седьмой вопрос задаёт уже не установщик, а сам набор: всё, что не отмечено, вычищается из конфигурации, шаблонов и тестов. Отсюда удобный приём — лишнее лучше отключить сразу, чем потом искать хвосты по проекту. Если же на первый вопрос ответить «нет», а стек всё равно выбрать, получится заготовка с React, Vue, Svelte или Livewire, но без авторизации.
Код набора целиком переносится в приложение, и никакой зависимости от пакета-шаблона не остаётся. Контроллеры, страницы и компоненты дальше живут как обычный код проекта — их можно свободно править.
Fortify и маршруты авторизации
Во всех наборах авторизацией занимается Laravel Fortify — бэкенд, у которого нет своего интерфейса. Он регистрирует маршруты /login, /logout, /register, /forgot-password, /reset-password, /email/verify, /user/confirm-password, /two-factor-challenge и ряд других, а страницы к ним поставляет набор. Посмотреть весь список можно командой php artisan route:list.
Какие функции включены, решает массив features в config/fortify.php:
use Laravel\Fortify\Features;
'features' => [
Features::registration(),
Features::resetPasswords(),
Features::emailVerification(),
Features::twoFactorAuthentication([
'confirm' => true, // 2FA активируется только после ввода кода
'confirmPassword' => true, // пароль спрашивается перед включением и отключением
]),
Features::passkeys([
'confirmPassword' => true,
]),
],
Регистрация и сброс пароля реализованы классами-действиями (actions) CreateNewUser и ResetUserPassword в app/Actions/Fortify. Правила валидации в последних версиях наборов переехали в трейты app/Concerns/PasswordValidationRules.php и ProfileValidationRules.php, хотя документация пока указывает для PasswordValidationRules старое место — app/Actions/Fortify.
Отключение открытой регистрации
Во внутренней CRM или админке посторонним регистрироваться незачем. Самый короткий путь — не отмечать «Registration» при установке. В уже созданном проекте хватит закомментировать функцию в config/fortify.php:
'features' => [
// Features::registration(), // регистрация выключена
Features::resetPasswords(),
// ...
],
Здесь есть подвох: маршрут register пропадает, а ссылки на него в шаблонах остаются. В Livewire-наборе страница входа ведёт на регистрацию напрямую, поэтому без правки /login начинает отвечать ошибкой 500 «Route [register] not defined». Ссылку в resources/views/pages/auth/login.blade.php нужно убрать или обернуть проверкой — второй вариант удобнее, если регистрацию когда-нибудь вернут:
@if (Route::has('register'))
<div class="space-x-1 text-sm text-center text-zinc-600 dark:text-zinc-400">
<span>{{ __('Don\'t have an account?') }}</span>
<flux:link :href="route('register')" wire:navigate>{{ __('Sign up') }}</flux:link>
</div>
@endif
В наборах на React, Vue и Svelte та же проблема всплывёт ещё на этапе сборки. Там работает Wayfinder: во время сборки он создаёт типизированные функции для маршрутов Laravel, а страницы их импортируют (import { register } from '@/routes'). Раз маршрута нет, npm run build будет падать, пока импорт и ссылки не удалены из компонентов. В каком-то смысле это даже удобнее: ошибка видна до деплоя, а не у пользователя.
Дополнительное поле в форме регистрации
Допустим, интернет-магазину при регистрации нужен телефон покупателя. Начинаем с миграции:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
// nullable — у существующих пользователей телефона нет
$table->string('phone', 20)->nullable()->after('email');
});
}
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('phone');
});
}
};
Дальше модель. В Laravel 13 User из набора перечисляет поля для массового заполнения не в свойстве $fillable, а атрибутом. Новое поле добавляется туда же — #[Fillable(['name', 'email', 'phone', 'password'])]. Если об этом забыть, User::create() просто пропустит телефон, без ошибок и предупреждений.
Затем правило валидации и сохранение в CreateNewUser. В модель стоит передавать только прошедшие проверку данные — результат validate(), а не весь $input:
public function create(array $input): User
{
$validated = Validator::make($input, [
...$this->profileRules(),
'phone' => ['required', 'string', 'regex:/^\+?[0-9\s\-()]{10,20}$/'],
'password' => $this->passwordRules(),
])->validate();
return User::create([
'name' => $validated['name'],
'email' => $validated['email'],
'phone' => $validated['phone'],
'password' => $validated['password'], // хеширование делает каст 'hashed' в модели
]);
}
Последний шаг — само поле в форме. У Livewire-набора она лежит в resources/views/pages/auth/register.blade.php:
<flux:input
name="phone"
:label="__('Телефон')"
:value="old('phone')"
type="tel"
required
autocomplete="tel"
placeholder="+7 900 123-45-67"
/>
В наборах на Inertia такое же поле добавляется на страницу регистрации в resources/js/pages.
2FA, passkeys, подтверждение email и команды
Двухфакторная аутентификация (2FA) по TOTP работает сразу после установки. Пользователь включает её в настройках, сканирует код любым приложением-аутентификатором и получает резервные коды. Опция confirm не позволяет активировать 2FA без проверочного кода, а confirmPassword запрашивает пароль при включении и отключении.
Весной 2026 года в Fortify появились passkeys — вход по WebAuthn через Face ID, Touch ID, Windows Hello или аппаратный ключ. Их включает Features::passkeys(), а модель User для этого реализует интерфейс PasskeyUser. В свежих версиях наборов passkeys включены изначально, отключить их можно тем же вопросом установщика. До этого войти без пароля в наборах можно было только через WorkOS.
За подтверждение email отвечают интерфейс MustVerifyEmail у модели User и middleware verified на маршрутах. Если функцию не отключать при установке, настраивать ничего не нужно: интерфейс уже подключён, а группа маршрутов с dashboard в routes/web.php защищена ['auth', 'verified'].
Команды (Teams) включаются ответом «да» в установщике или флагом --teams. Каждый пользователь получает личную команду, текущая команда отражается в URL (/{current_team}/dashboard), есть экраны для создания команд, переключения между ними и приглашения участников. Раньше ради этого ставили Jetstream.
Вариант с WorkOS AuthKit отдаёт авторизацию внешнему сервису: вход через Google, Microsoft, GitHub и Apple, Magic Auth и SSO. Понадобятся аккаунт WorkOS и ключи в .env.
Livewire-набор изнутри
Вся фронтенд-часть Livewire-набора сосредоточена в resources/views:
components— Blade-компоненты для повторного использования;flux— переопределённые компоненты Flux UI;layouts— шаблоны приложения и страниц входа;pages— Livewire-страницы:auth/*(вход, регистрация, сброс пароля) иsettings/*(профиль, внешний вид, безопасность);partials— общие куски разметки, например<head>;dashboard.blade.phpиwelcome.blade.php.
Страницы подключаются маршрутами вида Route::livewire('settings/profile', 'pages::settings.profile'). Если в старых туториалах встречается Volt, это не ошибка: в Laravel 12 Livewire-набор был построен на нём. Текущая версия обходится без Volt — она использует однофайловые компоненты Livewire 4.
Из коробки приложение открывается с боковой панелью (sidebar). Для горизонтального меню в resources/views/layouts/app.blade.php подключается другой layout, а flux:main получает атрибут container:
<x-layouts::app.header :title="$title ?? null">
<flux:main container>
{{ $slot }}
</flux:main>
</x-layouts::app.header>
Страницы входа бывают трёх видов: simple (по умолчанию), card и split. Нужный задаётся в resources/views/layouts/auth.blade.php:
<x-layouts::auth.split :title="$title ?? null">
{{ $slot }}
</x-layouts::auth.split>
Если интерфейсу нужно обновляться в реальном времени — уведомления, список заказов без перезагрузки страницы, — к набору подключается Reverb. Об этом отдельная статья: «Real-time в Laravel: Reverb и Echo».
Когда ещё нужен laravel/ui
laravel/ui генерирует каркас на Blade и Bootstrap, а авторизацию реализует контроллерами на трейтах. Новому проекту стартовые наборы дадут больше, но у пакета остаются свои ниши:
- проект уже сделан на
laravel/uiи Bootstrap, и переверстывать его ради смены инструмента бессмысленно; - требуется простая авторизация на чистом Blade — без Tailwind, Inertia и Livewire;
- учебный проект, где полезно видеть привычные контроллеры
LoginControllerиRegisterController.
Установка в Laravel 13:
composer require laravel/ui
php artisan ui bootstrap --auth # или: ui vue --auth, ui react --auth
npm install && npm run build # для разработки — npm run dev
Старые инструкции часто советуют npm run watch, но такой команды больше нет: сборку выполняет Vite, а режим разработки запускается через npm run dev. Маршруты авторизации подключает Auth::routes() в routes/web.php, и отдельные группы можно выключить параметрами:
Auth::routes([
'register' => false, // открытая регистрация выключена
'verify' => true, // маршруты подтверждения email
]);
Проверка на чистом Laravel 13 с laravel/ui 4.6.3 выявила две проблемы, о которых документация молчит:
-
Пресет подменяет
vite.config.jsи собираетresources/sass/app.scss, а стандартнаяwelcome.blade.phpвсё так же подключаетresources/css/app.css. В итоге послеnpm run buildглавная страница отдаёт 500 «Unable to locate file in Vite manifest». Исправляется это правкой подключения вwelcome.blade.phpили переводом страницы на layout из пресета:@vite(['resources/sass/app.scss', 'resources/js/app.js']) -
Пресет
vueставит@vitejs/plugin-vueверсии 5, а она не совместима с Vite 8 из свежего Laravel, поэтомуnpm installзавершается ошибкой ERESOLVE. Выручает обновление плагина:npm install -D @vitejs/plugin-vue@^6
Tailwind из стандартного package.json пресет не трогает — если проект переходит на Bootstrap, эти пакеты удаляются вручную. Во время сборки Bootstrap через Sass Dart Sass выводит предупреждения об устаревших функциях; на результат они не влияют и ошибками не считаются.
Об ограничениях laravel/ui лучше знать до старта: ни 2FA, ни passkeys, ни команд, нет классов-действий Fortify, вёрстка только на Bootstrap. Пресет React устанавливает React 18. Собственные пресеты можно описать через макросы UiCommand, но в новых проектах это почти не пригождается.
Что делать со старым проектом на Breeze, Jetstream или laravel/ui
Breeze, laravel/ui и стартовые наборы копируют код в приложение, так что «обновлять набор» не нужно — FAQ документации говорит об этом прямо. После перехода на Laravel 13 проект на Breeze или laravel/ui продолжит работать: оба пакета заявляют совместимость с illuminate/* 13.x. Jetstream привязывает приложение к себе сильнее, поскольку часть логики остаётся внутри пакета, но и он получил обновление под Laravel 13.
Инструмента для автоматического переезда с Breeze или Jetstream на новый набор нет. Если переезд всё-таки нужен, надёжнее всего развернуть чистое приложение на выбранном наборе и по частям переносить туда страницы авторизации и настроек, сверяя маршруты и их имена.
Браться за переписывание авторизации стоит, когда понадобились 2FA, passkeys или команды, фронтенд и так переводится на Tailwind, Livewire или Inertia либо проект отказывается от Bootstrap. Сам по себе переход на Laravel 13 поводом для этого не служит.
Итог
- Новый проект, команда из PHP-разработчиков — Livewire-набор: Blade, Flux UI и никакого отдельного фронтенда.
- Много логики на клиенте — React, Vue или Svelte на Inertia.
- Нужны 2FA, passkeys или команды — подойдёт любой из четырёх наборов: всё это уже заложено в Fortify и страницах набора.
- Старый проект на
laravel/ui, Breeze или Jetstream — Laravel обновляется, авторизация остаётся как есть. - Простая авторизация на Bootstrap —
laravel/uiпо-прежнему работает, если учесть две проблемы сборки, описанные выше.
Сразу после установки набора стоит подключить инструменты разработки: Debugbar и IDE Helper.