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.

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:
| File | Purpose |
|---|---|
artisan | Laravel's powerful command-line interface (CLI) for running migrations, cache clearing, generating files |
.env | Environment-specific configuration (database credentials, API keys, APP_KEY). Never commit to version control! |
composer.json | PHP dependency management via Composer, defines required packages |
package.json | JavaScript dependencies managed by npm/yarn for frontend assets |
phpunit.xml | PHPUnit testing configuration for automated tests |
vite.config.js | Vite 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.phpwhich manages all exceptions thrown in your application - Http/ - HTTP layer components (Controllers, Middleware, Requests)
Controllers/- Handle incoming requests, return responsesMiddleware/- 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.phpfor 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 Containercache/- 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=ProductSeeder6public/ 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/public7resources/ 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 build8routes/ Directory - Application Endpoints
The routes/ directory defines all HTTP endpoints for your application. Understanding routing is crucial for Laravel MVC architecture:
| Route File | Purpose | Middleware | Use Case |
|---|---|---|---|
web.php | Web routes with session state | web (CSRF, cookies, sessions) | Traditional web applications, forms |
api.php | Stateless API routes | api (rate limiting, no sessions) | RESTful APIs, mobile apps, SPAs |
console.php | Closure-based Artisan commands | None | Quick command definitions |
channels.php | Broadcast channel authorization | auth | WebSocket 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 datasessions/- File-based session storageviews/- 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:clear10tests/ 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 --coverage11vendor/ 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 installafter cloning projects to download dependencies - • Use
composer updatecarefully - 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.php3. Secure Sensitive Files and Directories
🔒 Security Checklist:
- ✅ Configure web server document root to
public/directory only - ✅ Never commit
.envfile to version control (use .env.example as template) - ✅ Set proper permissions:
chmod 755for directories,644for files - ✅ Make
storage/andbootstrap/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=Post5. 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=20000Conclusion: 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 andstorage/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. Create a fresh Laravel project and explore each directory hands-on
- 2. Practice using Artisan commands to generate controllers, models, and middleware
- 3. Implement Repository pattern and Service classes in your projects
- 4. Configure proper web server security pointing to
public/directory - 5. Learn advanced patterns like Domain-Driven Design for large applications
- 6. Explore Laravel packages to extend functionality
- 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)
📚 Related Resources:
Related Articles You May Like
- How to Become Web Developer: Essential Guide for Success
Career • Beginner
- How to Start Blogging on WordPress: A Step-by-Step Guide
WordPress • Beginner
- Master Git: 10 Essential Commands Every Developer Should Learn
Git • Beginner
- Laravel API Example: Creating Efficient Endpoints
Laravel • Advanced
- Laravel Tips and Tricks: Hidden Features Most Developers Miss
Laravel • Advanced
- How to Debug Laravel SQL Queries in API Requests: A Developer's Guide
Laravel • Intermediate