Reader Stacks

Laravel Eloquent Relationships: belongsTo, hasMany, and hasOne With Examples

Picking the wrong direction for a relationship — defining hasOne where belongsTo actually belongs — is the single most common beginner mistake, and it comes down to which table physically holds the foreign key.

Laravel Eloquent Relationships: belongsTo, hasMany, and hasOne With Examples

Eloquent's belongsTo, hasMany, and hasOne relationships each describe a different real-world data shape — getting the direction right depends entirely on which table physically holds the foreign key, which is the detail that trips up most beginners.

belongsTo: the "child" side of a relationship

// posts table has a user_id column
class Post extends Model
{
    public function author(): BelongsTo
    {
        return $this->belongsTo(User::class, 'user_id');
    }
}
$post->author->name;

belongsTo is defined on the model whose own table physically holds the foreign key column (posts.user_id here) — the method name (author) doesn't need to match the related model's name, but the foreign key column and, where needed, the related model class must be specified correctly.

hasMany: the "parent" side, with multiple children

class User extends Model
{
    public function posts(): HasMany
    {
        return $this->hasMany(Post::class, 'user_id');
    }
}
$user->posts; // a collection of all this user's posts

hasMany is the inverse of belongsTo — it's defined on the model that does NOT hold the foreign key, and it returns a collection since one user can have many posts.

hasOne: a one-to-one relationship

// profiles table has a user_id column
class User extends Model
{
    public function profile(): HasOne
    {
        return $this->hasOne(Profile::class, 'user_id');
    }
}

class Profile extends Model
{
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class, 'user_id');
    }
}
$user->profile->bio;

hasOne is structurally similar to hasMany — the foreign key still lives on the related table — but it returns a single model instance instead of a collection, since exactly one related row is expected.

The most common beginner mistake: picking the wrong direction

// WRONG — if posts.user_id is the foreign key, this direction is backwards
class User extends Model
{
    public function post(): BelongsTo
    {
        return $this->belongsTo(Post::class);
    }
}

The deciding question is always "which table's column points to the other table's primary key?" — whichever model's table holds that foreign key column is the one that gets belongsTo(); the other side always gets hasMany() or hasOne(), never the reverse.

Eager loading to avoid N+1 queries

$posts = Post::with('author')->get(); // 2 queries total, not N+1

foreach ($posts as $post) {
    echo $post->author->name;
}

Accessing $post->author inside a loop without eager loading first triggers one additional query per post (the N+1 problem) — with('author') loads every needed author in a single additional query up front instead.

Defining the inverse relationship

Every hasMany/hasOne relationship should typically have a corresponding belongsTo defined on the related model — while not strictly required if the inverse direction is never actually used in the app, defining both directions is the more complete, future-proof convention.