How to use UUIDs instead of auto-increment IDs in your Laravel app

UUIDs (Universally Unique Identifier) are 128 bits values, used to uniquely identify the table records. They are commonly represented as a hexadecimal string split into five groups separated by hyphens. A typical example looks like:

116c34de-3dcb-44bc-9511-a48242b9aaab

The point of this article is not to address the advantages or disadvantages of using UUIDs, but to see how to implement them in a Laravel app and update any foreign key based on a UUID column. For the purpose of this article, we are going to be using Laravel 7.x, but this can work on any other version of Laravel (Tested on 5.8 and 6.x). You can get the source code of this tutorial here.

Let’s start by creating a new Laravel app called laravel-uuid-demo.

composer create-project --prefer-dist laravel/laravel laravel-uuid-demo

This will create a new app with the latest Laravel version. If you want to specify a Laravel version, add the version number at the end like:

composer create-project --prefer-dist laravel/laravel your-project-name "7.0.*"

We are going to use the Ramsey UUID library, which is a package that helps generate universally unique identifiers.

NB: Since Laravel 5.6, Ramsey UUID is part of Laravel. No need to install it via Composer.

Image by author. Source: https://laravel.com/docs/5.6/releases#laravel-5.6

If you are using a version of Laravel below 5.6, run the following:

composer require ramsey/uuid

(Optional) Now let’s move the User model inside a Models folder and modify the namespace inside User.php from App to App\Models as shown below.

namespace App\Models;

Let’s create a trait for the UUID so that it can be easily re-usable throughout our app (Thanks to Wilbur Powery for this tip). We will import it in any Eloquent model that will require a UUID primary key. Create a new folder Traits, and create a new file Uuids.php

For any Laravel version from 5.6 and above, add the following code inside the Uuids.php trait:

<?phpnamespace App\Traits;use Illuminate\Support\Str;trait Uuids
{
/**
* Boot function from Laravel.
*/
protected static function boot()
{
parent::boot();
static::creating(function ($model) {
if (empty($model->{$model->getKeyName()})) {
$model->{$model->getKeyName()} = Str::uuid()->toString();
}
});
}
/**
* Get the value indicating whether the IDs are incrementing.
*
* @return bool
*/
public function getIncrementing()
{
return false;
}
/**
* Get the auto-incrementing key type.
*
* @return string
*/
public function getKeyType()
{
return 'string';
}
}

NB: For any Laravel version below 5.6, use the following trait instead:

<?phpnamespace App\Traits;use Ramsey\Uuid\Uuid;trait Uuids
{
/**
* Boot function from Laravel.
*/
protected static function boot()
{
parent::boot();
static::creating(function ($model) {
if (empty($model->{$model->getKeyName()})) {
$model->{$model->getKeyName()} = Uuid::uuid4()->toString();
}
});
}
/**
* Get the value indicating whether the IDs are incrementing.
*
* @return bool
*/
public function getIncrementing()
{
return false;
}
/**
* Get the auto-incrementing key type.
*
* @return string
*/
public function getKeyType()
{
return 'string';
}
}

Let’s unpack it: by convention, Eloquent assumes that the primary key on a model is an incrementing integer value. Since we are using UUID, we need to specify that the primary key is a string, and that it’s not an incrementing value. We do it by setting the $keyType to string, and $incrementing to false. Then we override the boot function of the model to use UUID.

Now, let’s import the trait into our User model. Your imports and Use statements should look like:

Next let’s transform our users migration to use UUID instead of auto-increments. Inside your CreateUsersTable migrations,

Replace

$table->id();

With

$table->uuid('id')->primary();

Now let’s run the migration: update your .env file by setting the database name, username and password. And create the database in your favourite environment. Then run:

php artisan migrate

Now we are ready to test. Let’s create some fake users using factory and seeders. By default, Laravel comes bundled with a UserFactory inside database/factories. If you have placed your User model inside a Models folder, update the import statement inside your UserFactory class from

use App\User;

To

use App\Models\User;

Then let’s create a seeder.

php artisan make:seeder UserSeeder

In the new generated class, import the User model and inside the run() function, add:

factory(User::class, 6)->create();

Your UserSeeder class should look like:

Open the DatabaseSeeder class inside the seeds folder, and uncomment/modify the line that calls the UserSeeder class. Your DatabaseSeeder class should look like:

Now let’s run the seeder. In your terminal, type:

php artisan db:seed

That’s it. Now let’s check the Users table to see the data generated.

(NB: remember_token, created_at, updated_at columns not shown)

You can see the id column uses UUID, and not the incremented id.

If you are using a UUID primary key as a foreign key in another table, you need to change the column type to uuid, where the foreign key is defined. For example: let’s assume every user has a profile. Your user_id column in the profiles table will need to change from

$table->bigInteger('user_id')->unsigned();

To

$table->uuid('user_id');

The profile migration will look something like:

(NB: the profile table primary key [id] does not need to be a UUID type.)

If you are building an API and using Laravel Passport or a Roles and permission package such as Laravel Spatie permission, you will need to publish the migrations and update the user_id column type to uuid.

Software developer. On twitter @MarieInnov

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store