Hi there! If you're working with Laravel 12 and need to set up a one-to-many relationship between database tables, this guide is for you. In this beginner-friendly tutorial, I’ll show you how to use Laravel’s Eloquent ORM to create a one-to-many relationship.
We’ll use a practical example: a User who can have many Posts. By the end, you’ll know how to define models, migrations, relationships, and retrieve related data.
In a one-to-many relationship, a single record in one table can be associated with multiple records in another table. For example:
User
can have many Posts
.Post
belongs to one User
.This is perfect for scenarios like blog posts, comments, or orders tied to a single user.
Before starting, ensure you have:
If you don’t have a project, create one with:
laravel new example-app
We’ll create two tables: users
and posts
. The posts
table will have a foreign key linking to the users
table.
Laravel provides a default users
migration. Check database/migrations
to ensure it exists and looks like this:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->string('password');
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('users');
}
};
Run this command to create a migration for the posts
table:
php artisan make:migration create_posts_table
Open the generated 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(): void
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id');
$table->string('title');
$table->text('content');
$table->timestamps();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});
}
public function down(): void
{
Schema::dropIfExists('posts');
}
};
Explanation:
user_id
is a foreign key linking to the users
table.onDelete('cascade')
ensures that if a user is deleted, their posts are also deleted.title
and content
store the post data.Run the migrations to create the tables:
php artisan migrate
Next, define the User
and Post
models and set up their relationships.
Open app/Models/User.php
and add the hasMany
relationship:
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Database\Eloquent\Relations\HasMany;
class User extends Authenticatable
{
protected $fillable = ['name', 'email', 'password'];
public function posts(): HasMany
{
return $this->hasMany(Post::class);
}
}
Explanation: The hasMany
method indicates that a User
can have multiple Posts
.
Run this command to create the Post
model:
php artisan make:model Post
Open app/Models/Post.php
and add the belongsTo
relationship:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Post extends Model
{
protected $fillable = ['user_id', 'title', 'content'];
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
}
The belongsTo
method indicates that a Post
belongs to a User
.
Let’s create a controller to test the one-to-many relationship and a route to access it.
Run:
php artisan make:controller UserController
Open app/Http/Controllers/UserController.php
and add:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\User;
use App\Models\Post;
class UserController extends Controller
{
public function index()
{
// Create a user
$user = User::create([
'name' => 'Jane Doe',
'email' => '[email protected]',
'password' => bcrypt('password'),
]);
// Create posts for the user
$user->posts()->createMany([
[
'title' => 'First Post',
'content' => 'This is my first post!',
],
[
'title' => 'Second Post',
'content' => 'This is my second post!',
],
]);
// Retrieve the user with their posts
$userWithPosts = User::with('posts')->first();
return response()->json([
'user' => $userWithPosts->name,
'email' => $userWithPosts->email,
'posts' => $userWithPosts->posts->map(function ($post) {
return [
'title' => $post->title,
'content' => $post->content,
];
}),
]);
}
}
Explanation:
createMany
.with('posts')
to eager-load the posts.Open routes/web.php
and add:
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;
Route::get('/test-relationship', [UserController::class, 'index'])->name('test.relationship');
Start your Laravel server:
php artisan serve
Visit http://localhost:8000/test-relationship
in your browser. You should see a JSON response like:
{
"user": "Jane Doe",
"email": "[email protected]",
"posts": [
{
"title": "First Post",
"content": "This is my first post!"
},
{
"title": "Second Post",
"content": "This is my second post!"
}
]
}
This confirms the one-to-many relationship is working!
You can access related data in various ways:
$user = User::find(1);
$posts = $user->posts; // Returns a collection of Posts
foreach ($posts as $post) {
echo $post->title; // Outputs: First Post, Second Post
}
$post = Post::find(1);
$user = $post->user; // Returns the associated User
echo $user->name; // Outputs: Jane Doe
Create a Blade file resources/views/user.blade.php
:
<!DOCTYPE html>
<html>
<head>
<title>Laravel 12 One-to-Many Relationship</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container mt-5">
<h3>{{ $user->name }}'s Posts</h3>
<p><strong>Email:</strong> {{ $user->email }}</p>
<h4>Posts:</h4>
<ul>
@foreach ($user->posts as $post)
<li>
<strong>{{ $post->title }}</strong>: {{ $post->content }}
</li>
@endforeach
</ul>
</div>
</body>
</html>
Update the UserController
to return the view:
public function index()
{
$user = User::with('posts')->first();
return view('user', compact('user'));
}
Implementing a one-to-many relationship in Laravel 12 is simple with Eloquent ORM! This tutorial showed you how to create migrations, define models, set up relationships, and retrieve related data using a User
and Posts
example.
Whether you’re building a blog, forum, or any app with related data, this approach keeps your database organized and efficient. I hope this guide was clear and helps you add one-to-many relationships to your Laravel projects.
Q1: What’s the difference between hasMany
and belongsTo
?
A: hasMany
is used on the model that owns multiple records (e.g., User
has many Posts
). belongsTo
is used on the model that is owned (e.g., Post
belongs to a User
).
Q2: Why use a separate posts
table?
A: A separate table organizes data better and allows a user to have multiple posts without cluttering the users
table. It’s also more scalable for large datasets.
Q3: What does onDelete('cascade')
do?
A: It ensures that if a user is deleted, all their associated posts are also deleted, maintaining data integrity.
Q4: How do I handle users with no posts?
A: The posts
relationship returns an empty collection if no posts exist. You can check with @if($user->posts->isEmpty())
in Blade or $user->posts->isEmpty()
in PHP.
Q5: Can I eager-load posts to improve performance?
A: Yes! Use User::with('posts')
to load posts in one query, reducing database queries compared to lazy loading.
You might also like: