Learn to create a simple blog management system with Laravel 11 in just 30 minutes. Perfect for beginners starting their Laravel journey.
Building your first Laravel application can seem overwhelming, but creating a simple CRUD (Create, Read, Update, Delete) system is the perfect way to understand Laravel’s core concepts. In this tutorial, we’ll build a basic blog post management system that will teach you the fundamentals of Laravel development.
What You’ll Learn
- Setting up a fresh Laravel project
- Creating models, migrations, and controllers
- Building views with Blade templating
- Implementing full CRUD functionality
- Basic form validation
- Routing in Laravel
Prerequisites
Before we start, make sure you have:
- PHP 8.1+ installed on your system
- Composer (PHP package manager)
- A code editor (VS Code recommended)
- Basic knowledge of PHP and HTML
Step 1: Setting Up Your Laravel Project
First, let’s create a new Laravel project using Composer:
composer create-project laravel/laravel blog-crud-app
cd blog-crud-app
Start the development server:
php artisan serve
Your Laravel application will be available at http://localhost:8000.
Step 2: Creating the Database and Migration
Laravel uses migrations to manage database schema. Let’s create a migration for our blog posts:
php artisan make:migration create_posts_table
Open the migration file in database/migrations/ and update it:
<?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->string('author');
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('posts');
}
};
Run the migration:
php artisan migrate
Step 3: Creating the Post Model
Generate a model for our blog posts:
php artisan make:model Post
Update the app/Models/Post.php file:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
use HasFactory;
protected $fillable = [
'title',
'content',
'author'
];
}
Step 4: Creating the Controller
Laravel controllers handle the business logic. Create a resource controller:
php artisan make:controller PostController --resource
Update app/Http/Controllers/PostController.php:
<?php
namespace App\Http\Controllers;
use App\Models\Post;
use Illuminate\Http\Request;
class PostController extends Controller
{
public function index()
{
$posts = Post::latest()->get();
return view('posts.index', compact('posts'));
}
public function create()
{
return view('posts.create');
}
public function store(Request $request)
{
$request->validate([
'title' => 'required|max:255',
'content' => 'required',
'author' => 'required|max:255'
]);
Post::create($request->all());
return redirect()->route('posts.index')
->with('success', 'Post created successfully!');
}
public function show(Post $post)
{
return view('posts.show', compact('post'));
}
public function edit(Post $post)
{
return view('posts.edit', compact('post'));
}
public function update(Request $request, Post $post)
{
$request->validate([
'title' => 'required|max:255',
'content' => 'required',
'author' => 'required|max:255'
]);
$post->update($request->all());
return redirect()->route('posts.index')
->with('success', 'Post updated successfully!');
}
public function destroy(Post $post)
{
$post->delete();
return redirect()->route('posts.index')
->with('success', 'Post deleted successfully!');
}
}
Step 5: Setting Up Routes
Add the resource routes to routes/web.php:
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PostController;
Route::get('/', function () {
return redirect()->route('posts.index');
});
Route::resource('posts', PostController::class);
Step 6: Creating the Views
Create the views directory and files:
mkdir resources/views/posts
Layout File (resources/views/layouts/app.blade.php)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@yield('title', 'Laravel CRUD App')</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container">
<a class="navbar-brand" href="{{ route('posts.index') }}">Blog CRUD</a>
</div>
</nav>
<div class="container mt-4">
@if(session('success'))
<div class="alert alert-success">
{{ session('success') }}
</div>
@endif
@yield('content')
</div>
</body>
</html>
Index View (resources/views/posts/index.blade.php)
@extends('layouts.app')
@section('title', 'All Posts - Laravel CRUD')
@section('content')
<div class="d-flex justify-content-between align-items-center mb-4">
<h1>All Blog Posts</h1>
<a href="{{ route('posts.create') }}" class="btn btn-primary">Create New Post</a>
</div>
@if($posts->count() > 0)
<div class="row">
@foreach($posts as $post)
<div class="col-md-6 mb-4">
<div class="card">
<div class="card-body">
<h5 class="card-title">{{ $post->title }}</h5>
<p class="card-text">{{ Str::limit($post->content, 100) }}</p>
<p class="text-muted">By {{ $post->author }} • {{ $post->created_at->diffForHumans() }}</p>
<div class="btn-group" role="group">
<a href="{{ route('posts.show', $post) }}" class="btn btn-sm btn-outline-primary">View</a>
<a href="{{ route('posts.edit', $post) }}" class="btn btn-sm btn-outline-secondary">Edit</a>
<form action="{{ route('posts.destroy', $post) }}" method="POST" class="d-inline">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-sm btn-outline-danger"
onclick="return confirm('Are you sure?')">Delete</button>
</form>
</div>
</div>
</div>
</div>
@endforeach
</div>
@else
<div class="text-center py-5">
<h3>No posts found</h3>
<p>Get started by creating your first blog post!</p>
<a href="{{ route('posts.create') }}" class="btn btn-primary">Create New Post</a>
</div>
@endif
@endsection
Create View (resources/views/posts/create.blade.php)
@extends('layouts.app')
@section('title', 'Create New Post - Laravel CRUD')
@section('content')
<div class="row justify-content-center">
<div class="col-md-8">
<h1>Create New Blog Post</h1>
@if ($errors->any())
<div class="alert alert-danger">
<ul class="mb-0">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<form action="{{ route('posts.store') }}" method="POST">
@csrf
<div class="mb-3">
<label for="title" class="form-label">Title</label>
<input type="text" class="form-control" id="title" name="title" value="{{ old('title') }}" required>
</div>
<div class="mb-3">
<label for="author" class="form-label">Author</label>
<input type="text" class="form-control" id="author" name="author" value="{{ old('author') }}" required>
</div>
<div class="mb-3">
<label for="content" class="form-label">Content</label>
<textarea class="form-control" id="content" name="content" rows="10" required>{{ old('content') }}</textarea>
</div>
<div class="mb-3">
<button type="submit" class="btn btn-primary">Create Post</button>
<a href="{{ route('posts.index') }}" class="btn btn-secondary">Cancel</a>
</div>
</form>
</div>
</div>
@endsection
Step 7: Testing Your CRUD Application
- Start your Laravel development server:
php artisan serve - Visit
http://localhost:8000 - Create a few blog posts using the “Create New Post” button
- Test editing and deleting posts
- Verify that validation works by submitting empty forms
Common Laravel CRUD Patterns You’ve Learned
Model-View-Controller (MVC) Architecture
- Model: Handles database interactions (
Post.php) - View: Manages presentation layer (Blade templates)
- Controller: Contains business logic (
PostController.php)
Eloquent ORM Features
Post::create()– Mass assignment for creating recordsPost::latest()– Ordering records by creation date- Route model binding – Automatic model injection
Blade Templating
- Template inheritance with
@extendsand@yield - Looping with
@foreach - Conditional rendering with
@if - Cross-site request forgery protection with
@csrf
Next Steps to Enhance Your Laravel Skills
- Add Image Upload: Learn file handling in Laravel
- Implement User Authentication: Use Laravel Breeze or Jetstream
- Add Categories: Create relationships between models
- API Development: Convert your CRUD to a REST API
- Testing: Write feature tests for your application
SEO Tips for Your Laravel Blog
- Use semantic HTML structure with proper heading hierarchy
- Implement meta descriptions and title tags dynamically
- Add Open Graph tags for social media sharing
- Consider adding breadcrumb navigation
- Optimize images with alt tags and proper sizing
Conclusion
Congratulations! You’ve successfully built your first Laravel CRUD application. This foundation gives you the essential knowledge to build more complex Laravel applications. The combination of Eloquent ORM, Blade templating, and Laravel’s routing system makes web development both powerful and enjoyable.
Key takeaways from this tutorial:
- Laravel’s convention over configuration approach speeds up development
- Resource controllers provide a clean structure for CRUD operations
- Blade templating makes creating dynamic views straightforward
- Laravel’s validation system helps maintain data integrity
Start experimenting with additional features like pagination, search functionality, or user authentication to continue your Laravel learning journey.



