Updated June 2026. Tested on Laravel 13 and PHP 8.4. The same idea works on older versions, only the migration helpers were shorter in the past.

A one to one relationship means one row in a table matches exactly one row in another table. You do not reach for it often, because if two tables always have a single matching row, you could usually keep that data in one table. But there are good reasons to split it.

A common case is keeping authentication data apart from profile data. The users table holds the email and password, and a separate profiles table holds the name, telephone and other details. That is the example we will build here.

The Profile model and migration

Generate the model along with its migration in one command.

php artisan make:model Profile -m

Open the new migration and describe the profiles table. The important line is the foreign key back to users.

public function up(): void
{
    Schema::create('profiles', function (Blueprint $table) {
        $table->id();
        $table->foreignId('user_id')->constrained()->cascadeOnDelete();
        $table->string('name');
        $table->string('telephone')->nullable();
        $table->timestamps();
    });
}

foreignId('user_id')->constrained() creates an unsigned user_id column and ties it to the id column on the users table. cascadeOnDelete() tells the database to remove the profile automatically when its user is deleted, so you never end up with an orphaned profile. Run the migration.

php artisan migrate

Define the relationship

You define a one to one relationship with a method on the model that returns hasOne. The method name is usually the singular of the related model.

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasOne;

class User extends Model
{
    public function profile(): HasOne
    {
        return $this->hasOne(Profile::class);
    }
}

Then define the inverse on the Profile model with belongsTo.

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Profile extends Model
{
    protected $fillable = ['name', 'telephone'];

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }
}

Eloquent assumes the foreign key is user_id, which matches what we created in the migration, so there is nothing else to wire up.

Read the related record

Once the relationship is defined, you reach the profile straight off the user. Because relationships chain, you can pull a single value in one line.

$telephone = User::find(212)->profile->telephone;

Notice the difference between profile and profile(). Using profile gives you the related model. Using profile() gives you the query builder, which you use when you want to add conditions or save a record.

Create the related record

Build the child and save it through the parent. Saving this way fills in the user_id for you.

$user = User::find(212);

$user->profile()->create([
    'name'      => 'Jane Perera',
    'telephone' => '614-867-5309',
]);

If you already have a Profile instance, use save instead.

$user->profile()->save($profile);

Delete the related record

To end the relationship, delete the profile through the user.

$user = User::find(212);
$user->profile()->delete();

And because we set cascadeOnDelete() on the foreign key earlier, deleting the user itself also clears the profile, with no extra step from you.

$user->delete(); // the profile goes too

That is the whole one to one relationship: a foreign key in the child table, hasOne on the parent, belongsTo on the child, and a cascade so nothing is left behind. If you have a question about one to one relationships in Laravel, leave a comment below.