Laravel Directory Structure Explained: Complete Guide for Beginners and Advanced Developers (2025)

Laravel has established itself as the most popular PHP framework in 2025, powering millions of web applications worldwide. With its elegant syntax, robust features like Eloquent ORM, Blade templating, and Artisan CLI, Laravel simplifies modern web development. However, understanding the Laravel directory structure is fundamental to building scalable, maintainable applications.

Whether you're a complete beginner learning Laravel MVC architecture or an experienced developer looking to master Laravel project structure best practices, this comprehensive guide covers everything you need to know about Laravel's folder organization, including the latest changes in Laravel 11 and Laravel 12.

Laravel Directory Structure Diagram - Complete Visual Guide

Why Does Laravel Have a Specific Directory Structure?

Laravel follows the Model-View-Controller (MVC) architectural pattern, a proven design paradigm that separates your application into three interconnected components:

  • Model: Handles data logic, database interactions via Eloquent ORM
  • View: Manages presentation layer using Blade templates
  • Controller: Processes HTTP requests, coordinates between Models and Views

This Laravel MVC architecture provides several critical benefits:

Benefits of Laravel's Directory Structure:

  • Code Organization: Clear separation of concerns keeps code modular and maintainable
  • Scalability: Easily scale from small blogs to enterprise-level e-commerce platforms
  • Team Collaboration: Standardized structure enables multiple developers to work efficiently
  • Debugging Efficiency: Organized files make troubleshooting faster and easier
  • Security by Design: Sensitive files isolated from public web access
  • Convention over Configuration: Reduces decision fatigue with sensible defaults

Understanding the Laravel folder structure is essential whether you're building a simple REST API, a complex SaaS application, or learning Laravel for beginners.


Laravel Directory Structure: Complete Breakdown (2025)

When you create a fresh Laravel project using composer create-project laravel/laravel my-app, you'll see a well-organized directory structure. Let's explore each folder in detail:

1Root Directory Files

The root directory contains essential configuration and bootstrapping files:

FilePurpose
artisanLaravel's powerful command-line interface (CLI) for running migrations, cache clearing, generating files
.envEnvironment-specific configuration (database credentials, API keys, APP_KEY). Never commit to version control!
composer.jsonPHP dependency management via Composer, defines required packages
package.jsonJavaScript dependencies managed by npm/yarn for frontend assets
phpunit.xmlPHPUnit testing configuration for automated tests
vite.config.jsVite bundler configuration for compiling frontend assets (replaces Laravel Mix)

2app/ Directory - The Heart of Your Application

The app/ directory contains your application's core business logic and is where you'll spend most of your development time. This is the "M" and "C" in the MVC pattern.

📁 app/ Subdirectories:

  • Console/ - Custom Artisan commands for task automation
    # Generate custom command
    php artisan make:command SendEmailReport
  • Exceptions/ - Global exception handling and custom exception classes

    Contains Handler.php which manages all exceptions thrown in your application

  • Http/ - HTTP layer components (Controllers, Middleware, Requests)
    • Controllers/ - Handle incoming requests, return responses
    • Middleware/ - Filter HTTP requests (authentication, CORS, etc.)
    • Requests/ - Form request validation classes
  • Models/ - Eloquent ORM models representing database tables
    # Generate model with migration and factory
    php artisan make:model Product -mf
  • Providers/ - Service providers that bootstrap application services

    Contains AppServiceProvider.php, RouteServiceProvider.php for service container bindings

💡 Pro Tip for Large Applications:

Create custom directories inside app/ for better organization: app/Services/, app/Repositories/, app/Traits/, app/Helpers/. Laravel's PSR-4 autoloading will automatically discover these classes.

3bootstrap/ Directory

The bootstrap/ directory initializes the Laravel framework. It contains:

  • app.php - Creates the application instance and binds the Service Container
  • cache/ - Framework-generated cache files for performance optimization (routes, config, services)

⚠️ Note: You rarely need to modify files in this directory unless you're customizing framework behavior.

4config/ Directory - Application Configuration

The config/ directory houses all configuration files for your Laravel application. Each file returns an array of configuration options:

Core Configuration Files:

  • 📄 app.php - Application name, environment, timezone, locale
  • 📄 database.php - Database connections (MySQL, PostgreSQL, SQLite)
  • 📄 cache.php - Cache drivers (Redis, Memcached, File)
  • 📄 session.php - Session configuration and drivers

Additional Configuration:

  • 📄 mail.php - Email services (SMTP, Mailgun, SES)
  • 📄 queue.php - Queue connections and drivers
  • 📄 filesystems.php - File storage (local, S3, FTP)
  • 📄 auth.php - Authentication guards and providers
// Example: Accessing configuration values
$appName = config('app.name');
$dbConnection = config('database.default');

// Setting configuration at runtime
config(['app.timezone' => 'America/New_York']);

5database/ Directory - Database Management

The database/ directory manages all database-related operations following version-controlled schema management:

📁 migrations/

Version-controlled database schema changes. Think of migrations as "version control for your database."

# Create a new migration
php artisan make:migration create_posts_table

# Run all pending migrations
php artisan migrate

# Rollback last migration
php artisan migrate:rollback

📁 factories/

Generate fake data for testing using Faker library. Essential for feature and unit tests.

// database/factories/UserFactory.php
public function definition(): array
{
    return [
        'name' => fake()->name(),
        'email' => fake()->unique()->safeEmail(),
        'password' => Hash::make('password'),
    ];
}

📁 seeders/

Populate your database with initial or test data. Perfect for development environments.

# Create a seeder
php artisan make:seeder ProductSeeder

# Run all seeders
php artisan db:seed

# Run specific seeder
php artisan db:seed --class=ProductSeeder

6public/ Directory - Web Root (Critical for Security)

The public/ directory is the ONLY folder that should be web-accessible. This is Laravel's document root and a critical security feature.

🔒 Security Critical Information:

  • index.php - Application entry point that bootstraps Laravel
  • .htaccess - Apache configuration for URL rewriting
  • Assets - CSS, JavaScript, images, fonts (compiled from resources/)
  • Storage Link - Symbolic link to storage/app/public for user uploads

⚠️ Web Server Configuration:

Always configure your web server (Nginx/Apache) document root to point to public/ directory, not the Laravel project root. This prevents direct access to sensitive files like .env, vendor/, and storage/.

# Create symbolic link for public file storage
php artisan storage:link

# This creates: public/storage -> storage/app/public

7resources/ Directory - Frontend Assets and Views

The resources/ directory contains raw, uncompiled assets and Blade templates (the "V" in MVC):

📁 views/

Blade template files (.blade.php) for rendering HTML. Supports template inheritance, components, and directives.

php artisan make:view posts.index

📁 lang/

Localization files for multi-language support. Organize translations by language (en/, es/, fr/).

{{ __('messages.welcome') }}

📁 css/ & js/

Source files for stylesheets and JavaScript. Compiled to public/ via Vite bundler.

npm run dev
npm run build

8routes/ Directory - Application Endpoints

The routes/ directory defines all HTTP endpoints for your application. Understanding routing is crucial for Laravel MVC architecture:

Route FilePurposeMiddlewareUse Case
web.phpWeb routes with session stateweb (CSRF, cookies, sessions)Traditional web applications, forms
api.phpStateless API routesapi (rate limiting, no sessions)RESTful APIs, mobile apps, SPAs
console.phpClosure-based Artisan commandsNoneQuick command definitions
channels.phpBroadcast channel authorizationauthWebSocket authentication, real-time
// routes/web.php - Example web routes
Route::get('/', function () {
    return view('welcome');
});

Route::get('/posts', [PostController::class, 'index'])->name('posts.index');
Route::resource('products', ProductController::class);

// routes/api.php - Example API routes (prefixed with /api)
Route::get('/users', [UserController::class, 'index']);
Route::post('/posts', [PostController::class, 'store'])->middleware('auth:sanctum');

9storage/ Directory - Generated Files and Logs

The storage/ directory stores application-generated files, caches, and logs. This directory must have write permissions.

🔐 CRITICAL SECURITY WARNING:

The storage/ directory must NEVER be publicly accessible. It contains sensitive information including:

  • • Application logs with error details and stack traces
  • • Session data potentially containing user information
  • • Cached configuration and compiled views
  • • User-uploaded private files

Configure your web server to deny direct access to this directory. Only files linked via storage:link command should be accessible through public/storage.

📁 storage/app/

Store application-generated files and user uploads:

  • public/ - Publicly accessible files (linked to public/storage)
  • private/ - Private files requiring authentication

📁 storage/framework/

Framework-generated files for optimization:

  • cache/ - Application cache data
  • sessions/ - File-based session storage
  • views/ - Compiled Blade templates for performance

📁 storage/logs/

Application log files for debugging and monitoring:

# View latest logs
tail -f storage/logs/laravel.log

# Clear old logs
php artisan log:clear

10tests/ Directory - Automated Testing

Laravel encourages Test-Driven Development (TDD) with built-in PHPUnit support. The tests/ directory contains your test suite:

📁 tests/Feature/

Integration tests for testing complete features, HTTP routes, database interactions, and user workflows.

php artisan make:test PostControllerTest

📁 tests/Unit/

Unit tests for isolated testing of individual classes, methods, and functions without external dependencies.

php artisan make:test UserTest --unit
# Run all tests
php artisan test

# Run specific test file
php artisan test --filter=PostControllerTest

# Run tests with coverage
php artisan test --coverage

11vendor/ Directory - Third-Party Dependencies

The vendor/ directory is managed by Composer and contains all third-party PHP packages including the Laravel framework itself.

⚠️ Important Rules:

  • Never manually edit files in vendor/ - Changes will be overwritten
  • Never commit vendor/ to Git - Use .gitignore (included by default)
  • Run composer install after cloning projects to download dependencies
  • Use composer update carefully - may introduce breaking changes

Laravel 11 vs Laravel 12: Directory Structure Changes

Laravel 11 introduced significant structural improvements focused on minimalism and developer experience. Laravel 12 continues this philosophy while adding new features.

🆕 Key Changes in Laravel 11+:

1. Removed HTTP and Console Kernels

app/Http/Kernel.php and app/Console/Kernel.php removed. Middleware now configured in bootstrap/app.php using fluent API.

// bootstrap/app.php (Laravel 11+)
return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        commands: __DIR__.'/../routes/console.php',
    )
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->web(append: [
            HandleInertiaRequests::class,
        ]);
    })->create();

2. Streamlined Middleware

Nine default middleware classes moved into the framework, reducing clutter in app/Http/Middleware/.

3. Simplified Service Providers

Most service providers consolidated. Only AppServiceProvider remains by default for custom bindings.

4. Optional config/ Publishing

Configuration files are optional. Publish only when customization is needed:

php artisan config:publish database

✅ Backward Compatibility:

Existing Laravel 10 applications continue to work without modification. You can gradually adopt new conventions or maintain the traditional structure. Laravel respects both approaches.


Understanding Service Container and Service Providers

The Service Container (also called IoC Container) and Service Providers are fundamental concepts in Laravel architecture that power dependency injection and application bootstrapping.

What is the Laravel Service Container?

The Service Container is Laravel's dependency injection container that manages class dependencies and performs automatic resolution. Think of it as a powerful factory that knows how to build objects.

// Automatic dependency injection in controller
class PostController extends Controller
{
    // Laravel automatically resolves and injects PostRepository
    public function __construct(
        protected PostRepository $repository
    ) {}
    
    public function index()
    {
        return $this->repository->all();
    }
}

// Manual container binding in AppServiceProvider
public function register(): void
{
    $this->app->bind(PostRepositoryInterface::class, EloquentPostRepository::class);
    
    // Singleton binding (single instance)
    $this->app->singleton(CacheManager::class, function ($app) {
        return new CacheManager($app['config']['cache']);
    });
}

What are Service Providers?

Service Providers are the central place for configuring your application. They register bindings in the Service Container and bootstrap services. Located in app/Providers/.

// app/Providers/AppServiceProvider.php
class AppServiceProvider extends ServiceProvider
{
    // Register bindings into the Service Container
    public function register(): void
    {
        $this->app->bind(PaymentGateway::class, StripeGateway::class);
    }
    
    // Bootstrap any application services
    public function boot(): void
    {
        // Configure View composers
        View::composer('profile', ProfileComposer::class);
        
        // Extend validators
        Validator::extend('strong_password', function($attribute, $value) {
            return preg_match('/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$/', $value);
        });
    }
}

Laravel Project Structure Best Practices (2025)

1. Follow "Fat Models, Skinny Controllers" Principle

Keep controllers focused on HTTP concerns. Move business logic to Service classes, Repository pattern, or Action classes.

❌ Bad Practice:

// Controller with too much logic
public function store(Request $request)
{
    $user = User::create($request->all());
    Mail::to($user)->send(new Welcome());
    event(new UserRegistered($user));
    Cache::forget('users_count');
    Log::info('User registered: '.$user->email);
    return redirect('/dashboard');
}

✅ Good Practice:

// Thin controller using service
public function store(
    StoreUserRequest $request,
    UserService $service
) {
    $user = $service->register($request->validated());
    return redirect('/dashboard');
}

2. Organize Code with Custom Directories

For large applications, create organized namespaces inside app/:

app/
├── Actions/              # Single-purpose action classes
│   └── User/
│       └── RegisterUser.php
├── Services/             # Business logic services
│   └── UserService.php
├── Repositories/         # Data access layer
│   └── UserRepository.php
├── Traits/               # Reusable traits
│   └── HasUuid.php
├── Helpers/              # Helper functions
│   └── StringHelper.php
├── DTOs/                 # Data Transfer Objects
│   └── UserData.php
└── Enums/                # PHP 8.1+ Enums
    └── UserRole.php

3. Secure Sensitive Files and Directories

🔒 Security Checklist:

  • ✅ Configure web server document root to public/ directory only
  • ✅ Never commit .env file to version control (use .env.example as template)
  • ✅ Set proper permissions: chmod 755 for directories, 644 for files
  • ✅ Make storage/ and bootstrap/cache/ writable: chmod -R 775
  • ✅ Keep Laravel and dependencies updated: composer update
  • ✅ Enable HTTPS in production with valid SSL certificate
  • ✅ Configure firewall rules to block direct access to sensitive directories
# Nginx configuration example
server {
    listen 80;
    server_name example.com;
    root /var/www/html/public;  # Point to public/ directory
    
    index index.php;
    
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
    
    # Deny access to sensitive files
    location ~ /\. {
        deny all;
    }
    
    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
    }
}

4. Leverage Artisan Commands for Consistency

Always use Artisan to generate files - ensures proper namespacing, boilerplate, and directory placement:

# Controllers
php artisan make:controller API/PostController --api
php artisan make:controller Admin/UserController --resource

# Models with relationships
php artisan make:model Post -mfsc  # migration, factory, seeder, controller

# Middleware
php artisan make:middleware CheckSubscription

# Form Requests for validation
php artisan make:request StorePostRequest

# Resources for API transformations
php artisan make:resource PostResource
php artisan make:resource PostCollection

# Jobs for queued tasks
php artisan make:job ProcessPodcast

# Events and Listeners
php artisan make:event OrderShipped
php artisan make:listener SendShipmentNotification

# Custom Artisan commands
php artisan make:command GenerateReport

# Policies for authorization
php artisan make:policy PostPolicy --model=Post

5. Implement Repository Pattern for Data Access

Separate data access logic from business logic using Repository pattern for testability and flexibility:

// app/Repositories/PostRepository.php
interface PostRepositoryInterface
{
    public function all();
    public function find($id);
    public function create(array $data);
}

class EloquentPostRepository implements PostRepositoryInterface
{
    public function __construct(protected Post $model) {}
    
    public function all()
    {
        return $this->model->latest()->paginate(15);
    }
    
    public function find($id)
    {
        return $this->model->findOrFail($id);
    }
    
    public function create(array $data)
    {
        return $this->model->create($data);
    }
}

// Register in AppServiceProvider
$this->app->bind(
    PostRepositoryInterface::class,
    EloquentPostRepository::class
);

6. Use Form Requests for Validation

Extract validation logic from controllers into dedicated Form Request classes:

// app/Http/Requests/StorePostRequest.php
class StorePostRequest extends FormRequest
{
    public function authorize(): bool
    {
        return $this->user()->can('create', Post::class);
    }
    
    public function rules(): array
    {
        return [
            'title' => ['required', 'string', 'max:255'],
            'content' => ['required', 'string'],
            'category_id' => ['required', 'exists:categories,id'],
            'tags' => ['array'],
            'tags.*' => ['string', 'max:50'],
            'published_at' => ['nullable', 'date', 'after:now'],
        ];
    }
    
    public function messages(): array
    {
        return [
            'title.required' => 'Please provide a post title',
            'content.required' => 'Post content cannot be empty',
        ];
    }
}

// Use in controller
public function store(StorePostRequest $request)
{
    $post = Post::create($request->validated());
    return redirect()->route('posts.show', $post);
}

7. Environment-Based Configuration

Never hardcode configuration values. Always use .env and config() helper:

❌ Bad:

// Hardcoded values
$apiKey = 'sk_test_abc123';
$url = 'https://api.stripe.com';

✅ Good:

// .env
STRIPE_KEY=sk_test_abc123
STRIPE_URL=https://api.stripe.com

// Usage
$apiKey = config('services.stripe.key');

Advanced Laravel Directory Structure for Enterprise Applications

For large-scale enterprise applications, consider implementing Domain-Driven Design (DDD) or modular architecture:

app/
├── Domain/                    # Domain layer (business logic)
│   ├── Blog/
│   │   ├── Models/
│   │   │   └── Post.php
│   │   ├── Actions/
│   │   │   ├── CreatePost.php
│   │   │   └── PublishPost.php
│   │   ├── QueryBuilders/
│   │   │   └── PostQueryBuilder.php
│   │   └── Events/
│   │       └── PostPublished.php
│   └── User/
│       ├── Models/
│       ├── Actions/
│       └── Events/
├── Application/              # Application layer
│   ├── Blog/
│   │   ├── Controllers/
│   │   ├── Requests/
│   │   ├── Resources/
│   │   └── Middleware/
│   └── User/
├── Infrastructure/           # Infrastructure layer
│   ├── Repositories/
│   ├── Cache/
│   └── External/
│       └── StripePayment.php
└── Support/                  # Supporting utilities
    ├── Helpers/
    ├── Traits/
    └── Macros/

📦 Package-Based Modular Structure:

For microservices-style monoliths, organize by business modules using Laravel packages:

packages/
├── Blog/
│   ├── src/
│   │   ├── BlogServiceProvider.php
│   │   ├── Models/
│   │   ├── Controllers/
│   │   └── routes/
│   ├── tests/
│   └── composer.json
└── Ecommerce/
    ├── src/
    ├── tests/
    └── composer.json

// Register in composer.json
"autoload": {
    "psr-4": {
        "App\\": "app/",
        "Packages\\Blog\\": "packages/Blog/src/",
        "Packages\\Ecommerce\\": "packages/Ecommerce/src/"
    }
}

Common Laravel Directory Structure Mistakes to Avoid

❌ Mistake #1: Putting Business Logic in Controllers

Controllers should be thin HTTP handlers, not business logic containers. Extract complex logic to Service classes or Action classes.

❌ Mistake #2: Not Using Form Requests

Validation logic clutters controllers. Always use Form Request classes for cleaner, reusable validation.

❌ Mistake #3: Exposing Sensitive Directories

Never point web server root to Laravel project root. Always configure document root to public/ directory.

❌ Mistake #4: Ignoring Artisan Commands

Creating files manually leads to namespace issues and missing boilerplate. Always use php artisan make: commands.

❌ Mistake #5: Hardcoding Configuration Values

Never hardcode API keys, database credentials, or environment-specific values. Use .env file and config() helper.

❌ Mistake #6: Not Understanding Service Container

The Service Container enables powerful dependency injection. Learn to use it instead of manual object instantiation.


Performance Optimization Tips for Laravel Directory Structure

⚡ Cache Configuration

# Cache config files
php artisan config:cache

# Cache routes
php artisan route:cache

# Cache views
php artisan view:cache

# Clear all caches
php artisan optimize:clear

⚡ Optimize Autoloader

# Production optimization
composer install --optimize-autoloader --no-dev

# Generate optimized class map
composer dump-autoload --optimize

⚡ Queue Long Tasks

// Move heavy operations to queues
SendEmailJob::dispatch($user);

// Use horizon for Redis queues
php artisan horizon

⚡ Use OPcache

; php.ini configuration
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000

Conclusion: Mastering Laravel Directory Structure in 2025

Understanding Laravel's directory structure is fundamental to becoming a proficient Laravel developer. This comprehensive guide has covered:

  • ✅ Complete breakdown of all Laravel directories (app/, public/, routes/, storage/, etc.)
  • Laravel MVC architecture principles and best practices
  • ✅ Security considerations for public/ folder and storage/ directory
  • ✅ Changes in Laravel 11 and Laravel 12 directory structure
  • Service Container and Service Provider concepts
  • ✅ Advanced organizational patterns for enterprise applications
  • ✅ Performance optimization techniques
  • ✅ Common mistakes to avoid

🚀 Next Steps in Your Laravel Journey:

  1. 1. Create a fresh Laravel project and explore each directory hands-on
  2. 2. Practice using Artisan commands to generate controllers, models, and middleware
  3. 3. Implement Repository pattern and Service classes in your projects
  4. 4. Configure proper web server security pointing to public/ directory
  5. 5. Learn advanced patterns like Domain-Driven Design for large applications
  6. 6. Explore Laravel packages to extend functionality
  7. 7. Join Laravel community forums and follow Laravel News

Whether you're building a simple blog, a robust e-commerce platform, or a complex SaaS application, Laravel's well-thought-out directory structure provides the foundation for clean, maintainable, and scalable code.

Start exploring your Laravel project structure today and unlock the full potential of modern PHP development! 🎉


Frequently Asked Questions (FAQ)

What is the purpose of the app/ directory in Laravel?+
Which Laravel folders should never be publicly accessible?+
Where are Laravel routes defined and what's the difference between web.php and api.php?+
What goes in Laravel's public/ folder and why is it important?+
How can I generate Laravel files quickly using Artisan commands?+
What are the main differences between Laravel 11 and Laravel 12 directory structure?+
What is the Service Container and Service Provider in Laravel?+
How do I organize code in large Laravel applications?+