UUID as primary key
Published: 2023-07-12 06:50:31

> This is a part of a series. Contact me if you find any mistakes or for any other input or questions

## Introduction

Have you ever deployed an application using the default primary keys in Laravel only to find out a week later that you have 10 million records in one table and suddenly worry about hitting the integer limit way earlier than expected?
Luckily Laravel has a great support for UUIDs in recent versions. Once you have decided to switch to UUIDs your next problem is to decide for a version. There is [a great post on dev.to by Viktor Dorotovič](https://dev.to/vdorot/uuids-are-bad-for-database-index-performance-enter-uuid7-4pbj) explaining the differences in detail, so I will not cover that here. The suitable versions for most of my use cases is UUID 4 and UUID 7, whereby native support with the on-board libraries for UUID 7 comes with Laravel 10. If you have an older version you can use version 4 instead, but version 7 is time sorted, so I will be using this one.

## Database Migrations

The first thing we have to do is adjusting our database migration. Per default a UUID column will have the name "uuid". I prefer to keep it to the default "id" column that a normal integer primary would have:

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

Next we have to adjust the foreign keys in other database tables linking to this column:

$table->foreignUuid('id');

Depending on the database you are using it will have native support for UUIDs. The advantage compared to a VARCHAR or TEXT is that it takes less storage space (16 bytes compared to 40 bytes using varchar). You can find more details in [this article](https://www.jacoelho.com/blog/2021/06/postgresql-uuid-vs-text/).

## Eloquent Model

As our primary key is not auto-incrementing anymore, we have to tell our Eloquent models about it and also automatically generate a new UUID when a new database record is created. The easiest way to do this is by using a trait.

You can create a new file in "[app\Traits\UUID.php](https://gist.github.com/patrickriemer/703c18c7804d25d15f825b1638176d20)" withe the contents of [this gist](https://gist.github.com/patrickriemer/703c18c7804d25d15f825b1638176d20). This will generate a new UUID whenever you are creating a new model and update the default incrementing and key type.

Now you can use the trait on any model you want to use the UUID for. You have to consider on which models to use it though as not each of them might need it. If you have a list of languages or countries for example you should stick to an integer as the amount of data in this table will never reach the volume that requires an UUID.

`<?php namespace App\Models;
use App\Traits\UUID;
class User
{
use UUID;
}`

If you should use the package Ramsey\Uuid a lot in your code you might want to name the trait differently or import it with an alias.

Don't forget to adjust the default migrations and models created by Laravel or packages like Jetstream as well.

## Migrating

The above will work fine for new projects, but what if you have an existing project that is outgrowing integer?
The best way is to add a new column "uuid" and "old_id" to all affected tables via migration, generate values for the UUID, making a copy of the former primary key into old_id and then setting the new uuid as primary key. After that you have to migrate all foreign keys in referencing tables which you can do with the old_id field. If you make use of cascading and foreign keys on database level, you have to turn of foreign key validation for this process.