Updated June 2026. Tested on Laravel 13 and PHP 8.4.
Imagine you need documents on several different things in your system: employees, customers, companies. The obvious approach is a separate documents table for each one, but they would all have the same shape, so you would be repeating yourself. A polymorphic relationship removes that repetition. One documents table serves every model, and each document knows which model and which record it belongs to.
We will add document support to an Employee and a Customer using a single Document model.
The documents table
Create the model and migration.
php artisan make:model Document -m
The two columns that make this work are documentable_id and documentable_type. Laravel gives you a helper that adds both at once.
public function up(): void
{
Schema::create('documents', function (Blueprint $table) {
$table->id();
$table->string('file_name');
$table->string('file_path')->nullable();
$table->string('description')->nullable();
$table->morphs('documentable');
$table->timestamps();
});
}
$table->morphs('documentable') adds documentable_id (the related record's id) and documentable_type (the related model's class name). So a document attached to employee 22 stores documentable_id = 22 and documentable_type = App\Models\Employee. That pair is how Laravel knows exactly what each document belongs to. Run the migration.
php artisan migrate
Define the relationship
On the Document model, add a morphTo method. Read morphTo as "belongs to, but the owner can be any model".
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphTo;
class Document extends Model
{
protected $fillable = ['file_name', 'file_path', 'description'];
public function documentable(): MorphTo
{
return $this->morphTo();
}
}
Then on each model that can own documents, add a morphMany pointing back at the documentable name.
use Illuminate\Database\Eloquent\Relations\MorphMany;
class Employee extends Model
{
public function documents(): MorphMany
{
return $this->morphMany(Document::class, 'documentable');
}
}
class Customer extends Model
{
public function documents(): MorphMany
{
return $this->morphMany(Document::class, 'documentable');
}
}
The two models share the exact same code, which is the whole point.
Save documents
Attach a document the same way for any owner. Saving through the relationship fills in both the id and the type.
$employee = Employee::find(22);
$employee->documents()->create([
'file_name' => 'passport-front.png',
'description' => 'Passport front page',
]);
$customer = Customer::find(39);
$customer->documents()->create([
'file_name' => 'invoice-may-2026.pdf',
'description' => 'Invoice for May 2026',
]);
Look in the table and you will see the type column doing its job.
id | file_name | documentable_id | documentable_type
1 | passport-front.png | 22 | App\Models\Employee
2 | invoice-may-2026.pdf| 39 | App\Models\Customer
Read documents
The documents come back as a collection, so reading them is the same on either model.
foreach ($employee->documents as $document) {
echo $document->file_name;
}
And from a document you can go back to its owner, whatever type it is.
$document = Document::find(1);
$owner = $document->documentable; // an Employee or a Customer
Polymorphic relationships save a lot of repeated work whenever several models need to share a feature like documents, notes or comments. One table, one model, and any number of owners. If you have a question about polymorphic relationships in Laravel, leave it in the comments.
All comments ()
No comments yet
Be the first to leave a comment on this post.