ホーム

Blog

Laravel Breeze Tutorial (Blade + Tailwind)

Laravel Breeze is a lightweight and elegant authentication starter kit for Laravel applications. It provides the essential features required for a modern authentication system using Blade and Tailwind

更新日:2025/10/27

Laravel Breeze Tutorial (Blade + Tailwind)

Introduction to Laravel Breeze

Laravel Breeze is a lightweight and elegant authentication starter kit for Laravel applications. It provides the essential features required for a modern authentication system using Blade templates and Tailwind CSS. Breeze is designed for developers who prefer simplicity, flexibility, and complete control over their code without the complexity of JavaScript-heavy stacks.

Breeze implements Laravel’s core authentication features, including registration, login, password reset, email verification, and password confirmation. It’s ideal for small and medium-sized applications, or as a foundation for more advanced setups.

Why Choose Laravel Breeze?

Laravel Breeze is part of Laravel’s official starter kits (alongside Jetstream, Fortify, and Spark). It focuses on simplicity while maintaining Laravel’s elegant structure. Some key advantages include:

  • ✅ Minimal and clean Blade templates.
  • ✅ Built-in authentication routes and controllers.
  • ✅ Tailwind CSS integration for modern, responsive UI.
  • ✅ Easy customization and extension.
  • ✅ Perfect for developers who prefer server-rendered apps.

Installation Guide

Before installing Laravel Breeze, ensure you have the following environment:

  • PHP 8.2 or higher
  • Composer
  • Node.js and npm
  • A new or existing Laravel project

Step 1 — Create a New Laravel Project

 composer create-project laravel/laravel breeze-demo cd breeze-demo 

Step 2 — Install Laravel Breeze

 composer require laravel/breeze --dev 

Step 3 — Scaffold Breeze (Blade Version)

Run the installation command and choose the Blade option when prompted:

 php artisan breeze:install 

This command will:

  • Publish the authentication routes, controllers, and views.
  • Install TailwindCSS configuration.
  • Update your package.json file with necessary dependencies.
  • Provide a ready-to-use authentication scaffold.

Step 4 — Install Frontend Dependencies

 npm install npm run dev 

Step 5 — Run Migrations

 php artisan migrate 

Step 6 — Start the Laravel Development Server

 php artisan serve 

Now visit http://127.0.0.1:8000/register. You should see a clean, Tailwind-styled registration form ready to use.

Understanding the Breeze Directory Structure

After installation, Laravel Breeze sets up a few important files and directories to handle authentication. Let’s explore the main ones:

1. Controllers

Located at app/Http/Controllers/Auth/, these controllers handle user login, registration, password reset, and logout.

Example — RegisteredUserController.php:

 namespace App\Http\Controllers\Auth; use App\Http\Controllers\Controller; use App\Models\User; use Illuminate\Http\Request; use Illuminate\Support\Facades\Hash; use Illuminate\Validation\Rules; class RegisteredUserController extends Controller { public function create() { return view('auth.register'); } public function store(Request $request) { $request->validate([ 'name' => ['required', 'string', 'max:255'], 'email' => ['required', 'string', 'email', 'max:255', 'unique:'.User::class], 'password' => ['required', 'confirmed', Rules\Password::defaults()], ]); $user = User::create([ 'name' => $request->name, 'email' => $request->email, 'password' => Hash::make($request->password), ]); auth()->login($user); return redirect()->intended(route('dashboard', absolute: false)); } } 

2. Routes

Breeze automatically registers authentication routes located in routes/auth.php and includes them in routes/web.php.

 Route::get('/register', [RegisteredUserController::class, 'create']) ->middleware('guest') ->name('register'); Route::post('/register', [RegisteredUserController::class, 'store']) ->middleware('guest'); 

3. Views (Blade Templates)

All the authentication views are located in resources/views/auth/.

Example — login.blade.php:

 <x-guest-layout> <form method="POST" action="{{ route('login') }}"> @csrf <div> <x-input-label for="email" :value="__('Email')" /> <x-text-input id="email" type="email" name="email" class="block mt-1 w-full" required autofocus /> <x-input-error :messages="$errors->get('email')" class="mt-2" /> </div> <div class="mt-4"> <x-input-label for="password" :value="__('Password')" /> <x-text-input id="password" type="password" name="password" class="block mt-1 w-full" required autocomplete="current-password" /> <x-input-error :messages="$errors->get('password')" class="mt-2" /> </div> <div class="block mt-4"> <label for="remember_me" class="inline-flex items-center"> <input id="remember_me" type="checkbox" name="remember" class="rounded border-gray-300"> <span class="ml-2 text-sm text-gray-600">{{ __('Remember me') }}</span> </label> </div> <div class="flex items-center justify-end mt-4"> @if (Route::has('password.request')) <a class="underline text-sm text-gray-600 hover:text-gray-900" href="{{ route('password.request') }}"> {{ __('Forgot your password?') }} </a> @endif <x-primary-button class="ml-3"> {{ __('Log in') }} </x-primary-button> </div> </form> </x-guest-layout> 

Authentication Flow in Laravel Breeze

Laravel Breeze leverages Laravel’s built-in authentication mechanisms powered by the Auth facade, guards, and middleware.

Here’s how the authentication process works:

  1. The user submits their credentials.
  2. Laravel validates the credentials using Auth::attempt().
  3. If the credentials match, a new session is generated.
  4. The user is redirected to the intended page (e.g., dashboard).

Example — AuthenticatedSessionController

 namespace App\Http\Controllers\Auth; use App\Http\Controllers\Controller; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; class AuthenticatedSessionController extends Controller { public function create() { return view('auth.login'); } public function store(Request $request) { $credentials = $request->validate([ 'email' => ['required', 'email'], 'password' => ['required'], ]); if (Auth::attempt($credentials, $request->boolean('remember'))) { $request->session()->regenerate(); return redirect()->intended('dashboard'); } return back()->withErrors([ 'email' => 'The provided credentials do not match our records.', ]); } public function destroy(Request $request) { Auth::logout(); $request->session()->invalidate(); $request->session()->regenerateToken(); return redirect('/'); } } 

6. Customizing Laravel Breeze

Laravel Breeze is intentionally minimal. However, it’s highly flexible and can be customized to match your project’s specific requirements. Let’s explore some of the most common customization techniques.

6.1 Customizing Registration

You can easily add extra fields to the registration form such as username, phone number, or role. Here’s how:

  1. Add new fields in the registration form view (resources/views/auth/register.blade.php).
  2. Update the registration controller (app/Http/Controllers/Auth/RegisteredUserController.php).
 <!-- resources/views/auth/register.blade.php --> <x-guest-layout> <form method="POST" action="{{ route('register') }}"> @csrf <!-- Name --> <div> <x-input-label for="name" :value="__('Name')" /> <x-text-input id="name" class="block mt-1 w-full" type="text" name="name" required autofocus autocomplete="name" /> <x-input-error :messages="$errors->get('name')" class="mt-2" /> </div> <!-- Username --> <div class="mt-4"> <x-input-label for="username" :value="__('Username')" /> <x-text-input id="username" class="block mt-1 w-full" type="text" name="username" required autocomplete="username" /> <x-input-error :messages="$errors->get('username')" class="mt-2" /> </div> <!-- Email Address --> <div class="mt-4"> <x-input-label for="email" :value="__('Email')" /> <x-text-input id="email" class="block mt-1 w-full" type="email" name="email" required autocomplete="username" /> <x-input-error :messages="$errors->get('email')" class="mt-2" /> </div> <!-- Password --> <div class="mt-4"> <x-input-label for="password" :value="__('Password')" /> <x-text-input id="password" class="block mt-1 w-full" type="password" name="password" required autocomplete="new-password" /> <x-input-error :messages="$errors->get('password')" class="mt-2" /> </div> <!-- Confirm Password --> <div class="mt-4"> <x-input-label for="password_confirmation" :value="__('Confirm Password')" /> <x-text-input id="password_confirmation" class="block mt-1 w-full" type="password" name="password_confirmation" required /> <x-input-error :messages="$errors->get('password_confirmation')" class="mt-2" /> </div> <div class="flex items-center justify-end mt-4"> <x-primary-button class="ml-4"> {{ __('Register') }} </x-primary-button> </div> </form> </x-guest-layout> 

Then update the controller:

 // app/Http/Controllers/Auth/RegisteredUserController.php public function store(Request $request) { $request->validate([ 'name' => 'required|string|max:255', 'username' => 'required|string|max:255|unique:users', 'email' => 'required|string|email|max:255|unique:users', 'password' => 'required|string|confirmed|min:8', ]); $user = User::create([ 'name' => $request->name, 'username' => $request->username, 'email' => $request->email, 'password' => Hash::make($request->password), ]); Auth::login($user); return redirect(RouteServiceProvider::HOME); } 

6.2 Adding Roles or Permissions

If your app requires roles (like admin, editor, user), you can integrate Spatie Laravel Permission or build a simple enum-based role system. Here’s a lightweight example:

 // database/migrations/add_role_to_users_table.php Schema::table('users', function (Blueprint $table) { $table->string('role')->default('user'); }); 

Then in your User model:

 // app/Models/User.php public function isAdmin() { return $this->role === 'admin'; } 

In your route or controller, you can now easily restrict access:

 Route::get('/admin', function () { abort_unless(Auth::user()?->isAdmin(), 403); return view('admin.dashboard'); }); 

6.3 Customizing Views with Tailwind

Because Laravel Breeze ships with Tailwind CSS, styling is straightforward. You can easily add components and modify layout files.

 <div class="bg-white rounded-lg shadow-md p-6"> <h2 class="text-xl font-semibold mb-4">Welcome Back!</h2> <p class="text-gray-600">You're logged in as {{ Auth::user()->name }}.</p> </div> 

7. Authentication Flow Deep Dive

Let’s look under the hood and understand how Breeze handles authentication in Laravel.

7.1 Login Flow

  1. User submits the login form.
  2. Laravel validates the credentials using Auth::attempt().
  3. If valid, Laravel regenerates the session ID to prevent fixation attacks.
  4. User is redirected to the intended dashboard route.
 // app/Http/Controllers/Auth/AuthenticatedSessionController.php public function store(Request $request) { $credentials = $request->validate([ 'email' => ['required', 'email'], 'password' => ['required'], ]); if (Auth::attempt($credentials, $request->boolean('remember'))) { $request->session()->regenerate(); return redirect()->intended(RouteServiceProvider::HOME); } return back()->withErrors([ 'email' => 'The provided credentials do not match our records.', ]); } 

7.2 Logout Flow

 public function destroy(Request $request) { Auth::guard('web')->logout(); $request->session()->invalidate(); $request->session()->regenerateToken(); return redirect('/'); } 

7.3 Password Reset Flow

Laravel Breeze includes password reset functionality by default. It uses Laravel’s built-in Password::sendResetLink and Password::reset methods.

 // app/Http/Controllers/Auth/PasswordResetLinkController.php public function store(Request $request) { $request->validate(['email' => 'required|email']); $status = Password::sendResetLink( $request->only('email') ); return $status === Password::RESET_LINK_SENT ? back()->with('status', __($status)) : back()->withErrors(['email' => __($status)]); } 

8. Extending Breeze with Frontend Enhancements

Although Breeze uses Blade Tailwind by default, you can gradually enhance your app with Alpine.js for interactivity.

8.1 Example: Show/Hide Password Toggle

 <div x-data="{ show: false }" class="relative"> <x-input-label for="password" :value="__('Password')" /> <input :type="show ? 'text' : 'password'" name="password" id="password" class="block mt-1 w-full"> <button type="button" @click="show = !show" class="absolute inset-y-0 right-0 px-3"> <span x-text="show ? 'Hide' : 'Show'"></span> </button> </div> 

9. Comparing Breeze vs Jetstream vs Fortify

FeatureBreezeJetstreamFortify
UI LayerBlade TailwindLivewire/InertiaAPI only (no UI)
ComplexityLightweightAdvancedLow-level
Best ForSmall to mid projectsFull-stack Laravel appsCustom authentication systems
2FA / API TokensNoYesConfigurable

10. Deployment and Security Tips

Before going live, consider the following recommendations:

  • Run php artisan optimize to cache routes and configs.
  • Use APP_ENV=production and APP_DEBUG=false.
  • Enforce HTTPS in AppServiceProvider.
  • Use Laravel Sanctum if you plan to add API endpoints.
  • Set proper session and cookie security flags in config/session.php.

11. Troubleshooting Common Issues

11.1 Tailwind CSS not applying styles

Ensure that you’ve run npm run dev and that your tailwind.config.js includes the correct content paths:

 // tailwind.config.js export default { content: [ './resources/**/*.blade.php', './resources/**/*.js', './resources/**/*.vue', ], theme: { extend: {}, }, plugins: [], } 

11.2 Login keeps redirecting

Check that RouteServiceProvider::HOME is set properly and that the auth middleware is applied correctly.

11.3 419 Page Expired

This typically happens due to missing CSRF tokens or session expiration. Ensure all forms include @csrf and cookies are being stored.

12. Advanced Example: Dashboard Customization

Let’s build a small dashboard to display user information after login:

 // routes/web.php Route::get('/dashboard', function () { return view('dashboard', ['user' => Auth::user()]); })->middleware(['auth', 'verified'])->name('dashboard'); 
 <x-app-layout> <x-slot name="header"> <h2 class="font-semibold text-xl text-gray-800 leading-tight"> {{ __('Dashboard') }} </h2> </x-slot> <div class="py-12"> <div class="max-w-7xl mx-auto sm:px-6 lg:px-8"> <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg"> <div class="p-6 text-gray-900"> {{ __('Hello, ') }} {{ $user->name }}! </div> </div> </div> </div> </x-app-layout> 

13. Conclusion

Laravel Breeze provides a perfect balance between simplicity and extensibility. It offers a ready-to-use authentication scaffolding that integrates beautifully with Blade and Tailwind CSS while keeping everything transparent and developer-friendly.

For developers seeking to build modern Laravel apps with authentication, registration, and password reset functionality — without unnecessary complexity — Laravel Breeze is the go-to choice.

From installation to customization, you now have the tools to build a secure and elegant authentication system. Start small, iterate, and customize as your application grows. Breeze ensures your foundation is solid and maintainable.

Next Steps

  • Integrate two-factor authentication via Fortify or Jetstream.
  • Upgrade your front-end using Inertia or Livewire.
  • Explore Laravel’s Sanctum for SPA/API authentication.

Final Thought: Laravel Breeze may be the simplest authentication starter kit, but its flexibility and clean architecture make it one of the most powerful tools in the Laravel ecosystem.