Skip to main content

What is a custom pivot model?

By default, the pivot table used by a belongsToMany (many-to-many) relationship is represented by a plain Illuminate\Database\Eloquent\Relations\Pivot instance. When you want to store extra columns on the pivot table (an approval timestamp, a role type, etc.), or add accessors, mutators, or custom methods, create a custom model that extends Pivot.
Call using() on your belongsToMany definition to tell the relationship to use this custom model.
When you save a custom pivot model, name it using the singular form of the two model names in alphabetical order (RoleUser, not UserRole). This is only a naming convention — you can pick any class name you like.

Specifying pivot attributes with as()

By default, pivot values are accessed through a pivot property. Use the as() method to change that name.

Extra columns and timestamps

When your pivot table has additional columns like approved, include them explicitly with withPivot(). Call withTimestamps() if you want Eloquent to manage created_at / updated_at.
Eloquent automatically updates the pivot table’s updated_at only when the pivot model is explicitly specified via using(). withTimestamps() also works with the default Pivot class, but pointing using() at a custom model unlocks custom events, custom casts, and more.

Inverse relationships from the pivot model

You are free to define belongsTo relationships back to the declaring model and the related model on your custom pivot.
With these in place, you can access $roleUser->role or $roleUser->user from a standalone pivot instance. If you want to automatically eager-load these when running the parent query, use the chaperone() method described below.

Automatic eager loading with chaperone() (Laravel 13)

Laravel 13 introduced the chaperone() method, which automatically hydrates belongsTo relationships defined on a pivot model — such as role() / user() — when the belongsToMany query runs.
When you call chaperone(), Eloquent infers the names of the belongsTo relationships on the pivot model (RoleUser) and, when you retrieve a collection with something like Role::with('users'), wires up references from each pivot to the declaring and related models with no additional queries.

Non-standard relationship names

If the belongsTo methods on your pivot model don’t follow the standard naming convention (singular camelCase of the declaring or related model name), pass explicit names as arguments to chaperone().
chaperone() extends N+1 prevention to references made through the pivot table. It works well alongside regular with() eager loading in applications that frequently read parent-model data through the pivot (for example, showing an approval timestamp next to a user name).

Next steps

Relationships

Review the basics of defining relationships, including belongsToMany.

Eloquent Observers and Model Events

Learn how to use model events to hook into saving and updating pivot models.
Last modified on September 11, 2026