Laravel is one of the most popular and elegant PHP frameworks used for building modern web applications. Its expressive syntax, structured organization, and powerful built-in tools make it a favorite among developers who seek clean, maintainable, and scalable codebases.
One of the first challenges beginners face is understanding the folder structure that appears after installing Laravel. This structure may look intimidating at first, but each folder serves a clear purpose, and once you know what goes where, everything becomes easier.
In this detailed guide, we will walk through the major directories in a fresh Laravel installation, focusing on:
- The
app/directory - The
routes/directory - The
resources/directory - The
database/directory
Along with explanations, we will also look at real code examples so you understand not just the theory but also practical usage.
Why Laravel’s Structure Matters
A well-organized framework ensures that developers can quickly navigate files, maintain code, and follow consistent conventions. Laravel’s philosophy emphasizes:
- Separation of concerns
- Clean architecture
- Reusability
- Readability
By understanding where your controllers, models, views, migrations, and routes live, you can start building projects with clarity and confidence.
app/ Directory – The Heart of Your Application
The app/ folder contains most of the core logic of your application. It houses:
- Models
- Controllers
- Middleware
- The application service provider
- Custom classes you build
It is often considered the central place where business logic resides.
The directory tree looks like this:
app/
Console/
Exceptions/
Http/
Controllers/
Middleware/
Requests/
Models/
Providers/
Let’s explore each subdirectory.
Models (app/Models)
Laravel uses Eloquent ORM, making database tables map directly to PHP classes called “models.”
A model represents a database table. For example, a users table corresponds to a User model.
Example Model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $fillable = [
'title',
'content'
];
}
In this example:
- The model represents a
poststable. - The
$fillableproperty defines which fields can be mass-assigned.
Models handle relationships, data retrieval, and database interaction.
Controllers (app/Http/Controllers)
Controllers group related request-handling logic. Instead of writing everything in routes, Laravel encourages moving logic into controllers.
A controller may look like this:
<?php
namespace App\Http\Controllers;
use App\Models\Post;
class PostController extends Controller
{
public function index()
{
return view('posts.index', [
'posts' => Post::all()
]);
}
}
In this example:
- The
index()method fetches all posts and sends them to a view. - Controllers communicate between routes and models.
Middleware (app/Http/Middleware)
Middleware filters HTTP requests entering your application.
Examples include:
- Authentication checks
- Logging
- Input trimming
- Request redirection
Example Middleware
<?php
namespace App\Http\Middleware;
use Closure;
class CheckAdmin
{
public function handle($request, Closure $next)
{
if (!auth()->user() || !auth()->user()->is_admin) {
abort(403);
}
return $next($request);
}
}
This middleware ensures only admin users can access certain routes.
routes/ Directory – Defining Application Entry Points
The routes/ folder defines all the URLs of your application. Each route maps a URL to:
- A controller method
- A closure
- A resource controller
- An API endpoint
The folder includes multiple files:
routes/
web.php
api.php
console.php
channels.php
Let’s explore the two most common ones.
web.php – Routes for Web Pages
web.php handles browser-based routes which use sessions and cookies.
Example Route
Route::get('/posts', [PostController::class, 'index']);
This route points /posts to the controller’s index method.
Closure-Based Route
Route::get('/', function () {
return view('welcome');
});
Route with Parameters
Route::get('/posts/{id}', function ($id) {
return "Post ID: " . $id;
});
api.php – Routes for APIs
api.php is designed for stateless endpoints typically consumed by front-end clients or mobile apps.
Example:
Route::get('/posts', function () {
return \App\Models\Post::all();
});
API routes automatically apply api middleware which handles rate-limiting and removes sessions.
resources/ Directory – Views, Assets, and Front-End Files
The resources/ directory contains everything related to the user interface:
- Blade template files
- CSS and JavaScript
- Localization strings
- React/Vue/Svelte resources (if installed)
The structure:
resources/
views/
css/
js/
lang/
Blade Templates (resources/views)
Blade is Laravel’s templating engine. It allows you to use clean syntax with features like:
- Template inheritance
- Loops
- Conditionals
- Components
Example Blade View
<!DOCTYPE html>
<html>
<head>
<title>Laravel Example</title>
</head>
<body>
<h1>{{ $title }}</h1>
@foreach ($posts as $post)
<h2>{{ $post->title }}</h2>
<p>{{ $post->content }}</p>
@endforeach
</body>
</html>
Blade files end with .blade.php.
CSS and JS (resources/css and resources/js)
Laravel uses Vite for asset bundling.
Example JS file (resources/js/app.js):
// Example JS code
console.log("Laravel JS Loaded");
Example CSS (resources/css/app.css):
body {
font-family: sans-serif;
}
Vite builds these assets into public/.
database/ Directory – Migrations, Seeders, Factories
The database/ folder manages everything related to your database structure and sample data.
Structure:
database/
migrations/
seeders/
factories/
Migrations (database/migrations)
Migrations create and modify database tables. Think of them as version control for the database.
Example Migration
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
public function up() {
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('content');
$table->timestamps();
});
}
public function down() {
Schema::dropIfExists('posts');
}
};
Run migrations using:
php artisan migrate
Seeders (database/seeders)
Seeders populate the database with initial or testing data.
Example Seeder
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use App\Models\Post;
class PostSeeder extends Seeder
{
public function run()
{
Post::create([
'title' => 'First Post',
'content' => 'This is an example post.'
]);
}
}
Run:
php artisan db:seed --class=PostSeeder
Factories (database/factories)
Factories generate fake data for testing.
Example Factory
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
class PostFactory extends Factory
{
public function definition()
{
return [
'title' => $this->faker->sentence(),
'content' => $this->faker->paragraph()
];
}
}
You can use it like:
Post::factory()->count(10)->create();
How These Folders Work Together
To understand the Laravel flow, consider this example:
- User visits
/posts - The route in
routes/web.phptriggersPostController@index - Controller fetches posts from
Postmodel - Controller passes data to the Blade view
- Blade template renders HTML with the data
Flow summary:
Route → Controller → Model → View → Browser
This clean separation ensures maintainable and testable code.
Practical Example: Creating a Basic Post Feature
Let’s build a small real-world example using the directories we learned.
Step 1: Migration
php artisan make:migration create_posts_table
Example migration:
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('content');
$table->timestamps();
});
Step 2: Model
php artisan make:model Post
app/Models/Post.php
class Post extends Model
{
protected $fillable = ['title', 'content'];
}
Step 3: Controller
php artisan make:controller PostController
public function index()
{
$posts = Post::all();
return view('posts.index', compact('posts'));
}
Step 4: Route
routes/web.php
Route::get('/posts', [PostController::class, 'index']);
Step 5: View
resources/views/posts/index.blade.php
<h1>All Posts</h1>
@foreach($posts as $post)
<h2>{{ $post->title }}</h2>
<p>{{ $post->content }}</p>
@endforeach
You now have a working page that fetches posts from the database and displays them.
Additional Important Directories in Laravel
Even though you asked for the most important ones, here is a brief overview of other helpful folders.
public/
Contains the entry point index.php and compiled assets like images, CSS, and JS after Vite builds them.
storage/
Handles logs, cached views, uploaded files, and compiled Blade templates.
config/
Stores all configuration files for:
- Database
- Cache
- Queue
- Session
- Services
Leave a Reply