How to use UUID in Laravel for primary keys?

Sushanta Pyakurel
4 min readFeb 25, 2022
user Migration with uuid

UUID stands for Universal Unique Identifier. It is 128 bits, 36-character alphanumeric label used to provide a unique identity to any collection of information within a computing system. This is getting popular and is replacing the traditional auto-increment numerical primary key for databases.

In this article, I am going to show you how to replace traditional auto-increment integers as the primary unique id with UUID in Laravel. You can use UUID for creating unique filenames or strings to be used for other database columns.

I am going to use ramsey/uuid library to generate a UUID to be used for our database column.

Install the UUID library.

composer require ramsey/uuid

Now let’s create a trait to use this UUID in the migrations and models. Create an app/Traits/Uuids.php file and paste the following code.

<?php

namespace App\Traits;

use Illuminate\Support\Str;

trait Uuids
{
/**
* Boot function from Laravel to create uuid for primary key.
*/
protected static function boot()
{
parent::boot();

static::creating(function ($model) {
if (empty($model->{$model->getKeyName()})) {
$model->{$model->getKeyName()} =
Str::uuid()->toString();
}
});
}

/**
* By default the auto increment is applied to id but we dont
* want it to happen for uuids as they are strings, not numbers
*
*
@return bool
*/
public function getIncrementing() : bool
{
return false;
}

/**
* By default the id number but uuids are string so we want to
* return string instead of number
*
*
@return string
*/
public function getKeyType() : string
{
return 'string';
}
}

This is the universal trait that we are going to use in all our Models. We are calling the boot method from Laravel and creating a UUID while the row is being created in the database table. setting the auto-increment of the primary key id as false and returning the id as a string instead of a number.

Now time to apply UUID to our migration file so that it creates a char(36) column for id in the database table.

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateUsersTable extends Migration
{
/**
* Run the migrations.
*
*
@return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->string('name');
$table->string('email')->unique();
$table->string('password');
$table->timestamp('email_verified_at')->nullable();
$table->rememberToken();
$table->timestamps();
});
}

/**
* Reverse the migrations.
*
*
@return void
*/
public function down()
{
Schema::dropIfExists('users');
}
}

Now we need to use this trait in our Models. So let’s use this in our User Model. You can use it for all the models in similar ways. Also, don't forget to cast id as a string.

<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use App\Traits\Uuids;

class User extends Authenticatable implements MustVerifyEmail
{
use HasApiTokens, HasFactory, Notifiable, Uuids;

/**
* The attributes that are mass assignable.
*
*
@var array<int, string>
*/
protected $fillable = [
'name'
'email',
'password'
];

/**
* The attributes that should be hidden for serialization.
*
*
@var array<int, string>
*/
protected $hidden = [
'password',
'remember_token',
];

/**
* The attributes that should be cast.
*
*
@var array<string, string>
*/
protected $casts = [
'email_verified_at' => 'datetime',
'id' => 'string',
];

}

That’s it. Now everything works as before except the primary key ids are UUID instead of regular auto-increment numbers.

Sometimes you might need to boot some models separately according to your requirements. Let’s say, you want to add User IP in the table whenever a row is created. You don’t need to pass the user IP from the controller. Instead you can use it inside the boot model. So if you use the boot method inside the Model, you need to add the codes from the boot method inside the Uuids trait as well.

<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use App\Traits\Uuids;

class User extends Authenticatable implements MustVerifyEmail
{
use HasApiTokens, HasFactory, Notifiable, Uuids;

/**
* The attributes that are mass assignable.
*
*
@var array<int, string>
*/
protected $fillable = [
'name'
'email',
'password'
];

/**
* The attributes that should be hidden for serialization.
*
*
@var array<int, string>
*/
protected $hidden = [
'password',
'remember_token',
];

/**
* The attributes that should be cast.
*
*
@var array<string, string>
*/
protected $casts = [
'email_verified_at' => 'datetime',
'id' => 'string',
];
/**
* Boot function from Laravel to create uuid for primary key.
*/
protected static function boot()
{
parent::boot();

static::creating(function ($user) {
if (empty($user->{$user->getKeyName()})) {
$user->{$user->getKeyName()} =
Str::uuid()->toString();
}
$user->user_ip = \Request::ip();
});
}}

--

--