• Fri, Mar 2026

Working with Relationships in Eloquent: One-to-One, One-to-Many, and Many-to-Many

Working with Relationships in Eloquent: One-to-One, One-to-Many, and Many-to-Many

In this comprehensive tutorial, we’ll explore how Laravel’s Eloquent ORM makes handling database relationships easy and powerful. From one-to-one associations to many-to-many connections, you’ll learn step by step how to define, query, and manage relationships with real-world examples.

Introduction

Databases are the backbone of most modern applications, and relationships between tables are what make them powerful. Laravel’s Eloquent ORM (Object-Relational Mapper) provides a clean, expressive syntax to define and query these relationships. Instead of writing complex SQL joins, you can interact with related models naturally using Eloquent’s methods.

In this guide, we will cover the three most commonly used relationships:

  • One-to-One
  • One-to-Many
  • Many-to-Many

Setting Up the Project

Let’s start by creating a new Laravel project:

composer create-project laravel/laravel eloquent-relationships

Set up the database in .env:


DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=eloquent_db
DB_USERNAME=root
DB_PASSWORD=
    

Understanding Eloquent Relationships

Eloquent provides helper methods to define relationships directly within models. These methods include:

MethodRelationship
hasOneOne-to-One
hasManyOne-to-Many
belongsToInverse of One-to-One / One-to-Many
belongsToManyMany-to-Many

One-to-One Relationship

A one-to-one relationship means that a record in one table is associated with exactly one record in another table. For example, a User has one Profile.

Step 1: Create Migrations

php artisan make:model User -m
php artisan make:model Profile -m

// database/migrations/xxxx_create_users_table.php
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamps();

// database/migrations/xxxx_create_profiles_table.php
$table->id();
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->string('phone')->nullable();
$table->text('bio')->nullable();
$table->timestamps();
    

Step 2: Define Relationship in Models


// app/Models/User.php
public function profile()
{
    return $this->hasOne(Profile::class);
}

// app/Models/Profile.php
public function user()
{
    return $this->belongsTo(User::class);
}
    

Step 3: Using the Relationship


// Create a user and profile
$user = User::create(['name' => 'Alice', 'email' => 'alice@example.com']);
$user->profile()->create(['phone' => '1234567890', 'bio' => 'Web Developer']);

// Accessing profile
$profile = $user->profile;

// Accessing user from profile
$user = Profile::find(1)->user;
    

One-to-Many Relationship

A one-to-many relationship means one record in a table can be associated with multiple records in another. Example: a Post can have many Comments.

Step 1: Create Models and Migrations

php artisan make:model Post -m
php artisan make:model Comment -m

// database/migrations/xxxx_create_posts_table.php
$table->id();
$table->string('title');
$table->text('content');
$table->timestamps();

// database/migrations/xxxx_create_comments_table.php
$table->id();
$table->foreignId('post_id')->constrained()->onDelete('cascade');
$table->string('author');
$table->text('comment');
$table->timestamps();
    

Step 2: Define Relationship in Models


// app/Models/Post.php
public function comments()
{
    return $this->hasMany(Comment::class);
}

// app/Models/Comment.php
public function post()
{
    return $this->belongsTo(Post::class);
}
    

Step 3: Using the Relationship


// Create a post and comments
$post = Post::create(['title' => 'My First Post', 'content' => 'Hello World!']);
$post->comments()->create(['author' => 'Bob', 'comment' => 'Great post!']);
$post->comments()->create(['author' => 'Jane', 'comment' => 'Thanks for sharing!']);

// Access comments
foreach ($post->comments as $comment) {
    echo $comment->author . ': ' . $comment->comment;
}

// Get post from a comment
$comment = Comment::find(1);
echo $comment->post->title;
    

Many-to-Many Relationship

A many-to-many relationship means multiple records in one table are related to multiple records in another. Example: a Student can enroll in many Courses, and a Course can have many Students.

Step 1: Create Models and Migrations

php artisan make:model Student -m
php artisan make:model Course -m

// database/migrations/xxxx_create_students_table.php
$table->id();
$table->string('name');
$table->timestamps();

// database/migrations/xxxx_create_courses_table.php
$table->id();
$table->string('title');
$table->timestamps();

// database/migrations/xxxx_create_course_student_table.php
$table->id();
$table->foreignId('student_id')->constrained()->onDelete('cascade');
$table->foreignId('course_id')->constrained()->onDelete('cascade');
$table->timestamps();
    

Step 2: Define Relationship in Models


// app/Models/Student.php
public function courses()
{
    return $this->belongsToMany(Course::class);
}

// app/Models/Course.php
public function students()
{
    return $this->belongsToMany(Student::class);
}
    

Step 3: Using the Relationship


// Attach students to courses
$student = Student::create(['name' => 'Emma']);
$course1 = Course::create(['title' => 'Math 101']);
$course2 = Course::create(['title' => 'Science 101']);

$student->courses()->attach([$course1->id, $course2->id]);

// Retrieve student's courses
foreach ($student->courses as $course) {
    echo $course->title;
}

// Retrieve course's students
foreach ($course1->students as $student) {
    echo $student->name;
}
    

Pivot Tables and Extra Fields

In many-to-many relationships, the pivot table can store additional data such as enrollment date.


// database/migrations/xxxx_create_course_student_table.php
$table->id();
$table->foreignId('student_id')->constrained()->onDelete('cascade');
$table->foreignId('course_id')->constrained()->onDelete('cascade');
$table->date('enrolled_at');
$table->timestamps();
    

// Accessing pivot data
foreach ($student->courses as $course) {
    echo $course->pivot->enrolled_at;
}
    

Eager Loading Relationships

To avoid the N+1 query problem, use eager loading:


$posts = Post::with('comments')->get();
    

Best Practices

  • Always name pivot tables using singular model names in alphabetical order (e.g., course_student).
  • Use eager loading for efficiency when retrieving relationships.
  • Leverage Laravel factories and seeders for testing relationships.
  • Keep relationship logic inside models for clarity.

Conclusion

Laravel’s Eloquent ORM makes working with relationships intuitive and elegant. By mastering one-to-one, one-to-many, and many-to-many relationships, you unlock the full potential of relational databases. Whether building user profiles, blog systems, or course enrollments, Eloquent provides the tools to structure your application’s data effectively.

In real-world applications, you’ll often combine these relationships, and Laravel makes it seamless to work with even the most complex database structures. With the knowledge gained here, you’re now equipped to design clean and scalable database relationships in your Laravel projects.

This website uses cookies to enhance your browsing experience. By continuing to use this site, you consent to the use of cookies. Please review our Privacy Policy for more information on how we handle your data. Cookie Policy