Skip to main content

Overview

Laravel Breeze API + Next.js uses a monorepo structure that separates the backend and frontend into distinct directories while keeping them in a single repository. This approach provides clear separation of concerns while maintaining ease of development.

Repository Structure

LaravelBreezeApi_Nextjs/
├── Backend/                    # Laravel 12 API
│   ├── app/
│   ├── bootstrap/
│   ├── config/
│   ├── database/
│   ├── public/
│   ├── resources/
│   ├── routes/
│   ├── storage/
│   ├── tests/
│   ├── .env.example
│   ├── artisan
│   ├── composer.json
│   └── phpunit.xml

├── Frontend/                   # Next.js 16 Application
│   ├── public/
│   ├── src/
│   ├── .env.example
│   ├── next.config.js
│   ├── package.json
│   ├── tailwind.config.ts
│   └── tsconfig.json

├── .editorconfig
├── .git/
├── CONTRIBUTING.md
├── LICENSE.md
└── README.md

Backend Structure (Laravel)

Core Directories

Contains the core application code including controllers, models, and middleware.
app/
├── Http/
│   ├── Controllers/
│   │   ├── Auth/                        # Authentication controllers
│   │   │   ├── AuthenticatedSessionController.php
│   │   │   ├── EmailVerificationNotificationController.php
│   │   │   ├── NewPasswordController.php
│   │   │   ├── PasswordResetLinkController.php
│   │   │   ├── RegisteredUserController.php
│   │   │   └── VerifyEmailController.php
│   │   └── Controller.php               # Base controller
│   ├── Middleware/
│   │   └── EnsureEmailIsVerified.php    # Email verification middleware
│   └── Requests/
│       └── Auth/
│           └── LoginRequest.php         # Login validation request
├── Models/
│   └── User.php                         # User Eloquent model
└── Providers/
    └── AppServiceProvider.php           # Application service provider
Defines all API endpoints and authentication routes.
routes/
├── api.php          # Protected API routes (requires auth:sanctum)
├── auth.php         # Authentication routes (register, login, logout)
├── console.php      # Artisan console commands
└── web.php          # Web routes (minimal for API-only)
api.php - Protected API routes:
Route::middleware(['auth:sanctum'])->get('/user', function (Request $request) {
    return $request->user();
});
auth.php - Authentication endpoints:
Route::post('/register', [RegisteredUserController::class, 'store'])
    ->middleware('guest');

Route::post('/login', [AuthenticatedSessionController::class, 'store'])
    ->middleware('guest');

Route::post('/logout', [AuthenticatedSessionController::class, 'destroy'])
    ->middleware('auth');
Contains all Laravel configuration files.
config/
├── app.php           # Application settings
├── auth.php          # Authentication configuration
├── cache.php         # Cache configuration
├── cors.php          # CORS settings for API
├── database.php      # Database connections
├── filesystems.php   # File storage configuration
├── logging.php       # Logging configuration
├── mail.php          # Email configuration
├── queue.php         # Queue configuration
├── sanctum.php       # Sanctum authentication config
├── services.php      # Third-party services
└── session.php       # Session configuration
Key Configuration: cors.php
return [
    'paths' => ['*'],
    'allowed_methods' => ['*'],
    'allowed_origins' => [env('FRONTEND_URL', 'http://localhost:3000')],
    'supports_credentials' => true,
];
Contains migrations, seeders, and factories for database management.
database/
├── factories/
│   └── UserFactory.php                              # User model factory
├── migrations/
│   ├── 0001_01_01_000000_create_users_table.php     # Users table
│   ├── 0001_01_01_000001_create_cache_table.php     # Cache table
│   ├── 0001_01_01_000002_create_jobs_table.php      # Queue jobs table
│   └── 2026_02_06_051602_create_personal_access_tokens_table.php
└── seeders/
    └── DatabaseSeeder.php                           # Main seeder
Contains feature and unit tests using Pest PHP.
tests/
├── Feature/
│   ├── Auth/
│   │   ├── AuthenticationTest.php
│   │   ├── EmailVerificationTest.php
│   │   ├── PasswordResetTest.php
│   │   └── RegistrationTest.php
│   └── ExampleTest.php
├── Unit/
│   └── ExampleTest.php
├── Pest.php          # Pest configuration
└── TestCase.php      # Base test case
Contains application-generated files, logs, and cached data.
storage/
├── app/              # Application files
├── framework/        # Framework cache and sessions
│   ├── cache/
│   ├── sessions/
│   └── views/
└── logs/             # Application logs
    └── laravel.log
Contains application bootstrap and caching files.
bootstrap/
├── app.php           # Application bootstrap
├── cache/            # Bootstrap cache
└── providers.php     # Service providers cache

Key Backend Files

{
    "name": "laravel/laravel",
    "type": "project",
    "description": "Laravel Breeze API with Sanctum authentication",
    "require": {
        "php": "^8.2",
        "laravel/framework": "^12.0",
        "laravel/sanctum": "^4.0",
        "laravel/tinker": "^2.9"
    },
    "require-dev": {
        "laravel/breeze": "^2.0",
        "pestphp/pest": "^3.0",
        "pestphp/pest-plugin-laravel": "^3.0"
    }
}

Frontend Structure (Next.js)

Core Directories

Next.js 16 App Router structure with route groups and layouts.
src/app/
├── (authenticated)/            # Protected routes group
│   ├── dashboard/
│   │   └── page.tsx           # Dashboard page
│   └── layout.tsx             # Authenticated layout with navigation

├── (guest)/                   # Guest routes group
│   ├── forgot-password/
│   │   └── page.tsx           # Forgot password page
│   ├── login/
│   │   └── page.tsx           # Login page
│   ├── password-reset/
│   │   └── [token]/
│   │       └── page.tsx       # Password reset page
│   └── register/
│       └── page.tsx           # Registration page

├── favicon.ico                # Application favicon
├── globals.css                # Global styles
├── layout.tsx                 # Root layout
├── not-found.tsx              # 404 page
└── page.tsx                   # Home page
Route groups (authenticated) and (guest) organize routes without affecting the URL structure.
Reusable React components organized by feature.
src/components/
└── Layouts/
    ├── Navigation.tsx         # Main navigation component
    ├── GuestLayout.tsx        # Guest layout wrapper
    └── AppLayout.tsx          # Authenticated app layout
Custom React hooks for authentication and data fetching.
src/hooks/
└── auth.ts                    # useAuth hook for authentication
useAuth Hook:
export const useAuth = ({
  middleware,
  redirectIfAuthenticated,
}: {
  middleware?: string
  redirectIfAuthenticated?: string
}) => {
  // SWR for user data fetching
  const { data: user, error, mutate } = useSWR('/api/user', ...)
  
  return {
    user,
    register,
    login,
    forgotPassword,
    resetPassword,
    resendEmailVerification,
    logout,
  }
}
Library code, utilities, and API client configuration.
src/lib/
└── axios.ts                   # Axios instance with base configuration
Axios Configuration:
const axios: AxiosInstance = Axios.create({
  baseURL: process.env.NEXT_PUBLIC_BACKEND_URL,
  headers: {
    'X-Requested-With': 'XMLHttpRequest',
  },
  withCredentials: true,
  withXSRFToken: true,
})
TypeScript type definitions and interfaces.
src/types/
└── index.ts                   # Shared type definitions
Static files served directly by Next.js.
public/
├── images/
├── icons/
└── favicon.ico

Key Frontend Files

{
  "name": "laravel-breeze-nextjs",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "react": "^18",
    "react-dom": "^18",
    "next": "^16",
    "axios": "^1.6.0",
    "swr": "^2.2.0",
    "formik": "^2.4.0",
    "yup": "^1.3.0"
  },
  "devDependencies": {
    "typescript": "^5",
    "@types/node": "^20",
    "@types/react": "^18",
    "tailwindcss": "^3.4.0",
    "eslint": "^8",
    "eslint-config-next": "^16"
  }
}

Route Groups Explained

Authenticated Routes (authenticated)/

Routes that require user authentication:
src/app/(authenticated)/layout.tsx
'use client'
import { ReactNode } from 'react'
import { useAuth } from '@/hooks/auth'
import Navigation from '@/components/Layouts/Navigation'

const AppLayout = ({ children }: { children: ReactNode }) => {
  const { user } = useAuth({ middleware: 'auth' })

  return (
    <div className="min-h-screen bg-gray-100">
      <Navigation user={user} />
      <main>{children}</main>
    </div>
  )
}

export default AppLayout
The middleware: 'auth' parameter in the useAuth hook automatically redirects unauthenticated users to the login page.

Guest Routes (guest)/

Routes accessible only to unauthenticated users (login, register, etc.):
  • /login - User login
  • /register - User registration
  • /forgot-password - Password reset request
  • /password-reset/[token] - Password reset form
Guest routes automatically redirect authenticated users to the dashboard.

Development Workflow

Running the Application

File Organization Best Practices

Controllers

Backend: Keep controllers thin, delegate to services
app/Http/Controllers/
app/Services/

Components

Frontend: Organize by feature or domain
src/components/Auth/
src/components/Dashboard/
src/components/Layouts/

Business Logic

Backend: Use service classes and actions
app/Services/
app/Actions/

Shared Types

Frontend: Define shared types centrally
src/types/models.ts
src/types/api.ts

Configuration Files

Backend Configuration

Defines PHP dependencies and scripts.
{
  "scripts": {
    "dev": "concurrently \"php artisan serve\" \"php artisan queue:listen\" \"npm --prefix ../Frontend run dev\"",
    "test": "pest"
  }
}

Frontend Configuration

Next.js configuration.
module.exports = {
  reactStrictMode: true,
  images: {
    domains: ['localhost'],
  },
}

Adding New Features

Backend: Adding a New API Endpoint

1

Create Controller

php artisan make:controller Api/PostController --api
2

Define Route

routes/api.php
Route::middleware(['auth:sanctum'])->group(function () {
    Route::apiResource('posts', PostController::class);
});
3

Create Model & Migration

php artisan make:model Post -m
4

Run Migration

php artisan migrate

Frontend: Adding a New Page

1

Create Page File

# For authenticated route
touch src/app/(authenticated)/posts/page.tsx
2

Create Component

src/app/(authenticated)/posts/page.tsx
'use client'
import { useAuth } from '@/hooks/auth'

export default function PostsPage() {
  const { user } = useAuth({ middleware: 'auth' })
  
  return (
    <div>
      <h1>Posts</h1>
    </div>
  )
}
3

Add Navigation Link

Update navigation component to include the new route.

Testing Structure

Backend Tests (Pest)

tests/Feature/Auth/AuthenticationTest.php
test('users can authenticate using the login screen', function () {
    $user = User::factory()->create();

    $response = $this->post('/login', [
        'email' => $user->email,
        'password' => 'password',
    ]);

    $this->assertAuthenticated();
    $response->assertNoContent();
});

Frontend Testing

Use Jest and React Testing Library for frontend tests:
import { render, screen } from '@testing-library/react'
import LoginPage from '@/app/(guest)/login/page'

test('renders login form', () => {
  render(<LoginPage />)
  expect(screen.getByText('Login')).toBeInTheDocument()
})

Build & Deployment

Backend Build

cd Backend
composer install --no-dev --optimize-autoloader
php artisan config:cache
php artisan route:cache
php artisan view:cache

Frontend Build

cd Frontend
npm run build
npm start

Next Steps

Architecture Overview

Learn about the full-stack architecture

Authentication

Deep dive into authentication flow

Build docs developers (and LLMs) love