Implementing UUID Primary Keys in Laravel: My Experience and Best Practices
Using UUIDs as primary keys in Laravel can provide significant benefits, such as enhanced security, scalability, and easier data management. While UUIDs are not exclusive to Laravel or MySQL, they are a great choice when designing applications that need unique and globally distinct identifiers. In this article, I’ll walk you through how to implement UUIDs in Laravel, share the challenges I faced, and discuss the solutions I found.
Why Use UUIDs?
UUIDs are particularly useful in distributed systems where unique identifiers are required across multiple databases or microservices. They help avoid ID collisions without needing a central authority. However, they also bring complexity to database design and management, which we’ll address step-by-step.
Step 1: Modifying Migrations
To use UUIDs, the first thing you need to modify is how you define primary keys in your migrations. Laravel’s usual shorthand for defining primary keys ($table->id()) won’t work here, as it generates an auto-increment integer. Instead, use:
$table->uuid('id')->primary();This command ensures that your primary key column, id, stores UUIDs instead of integers.
Handling Foreign Keys with UUIDs
Referencing records with UUIDs requires a different approach. For foreign keys, use:
$table->foreignUuid('user_id')->constrained();This tells Laravel to use a UUID to reference the user_id in another table. If the default behavior doesn’t fit, you can specify the table and column explicitly using references() and on().
Step 2: Adjusting the Model
By default, Laravel models assume integer primary keys. Here’s how to adjust your model:
Set $keyType to 'string' to indicate the key is a UUID:
protected $keyType = 'string';Disable auto-incrementing:
public $incrementing = false;Step 3: Generating UUIDs Automatically
When creating records, you need to ensure UUIDs are generated automatically. You can either manually assign a UUID using Str::uuid() each time you create a record:
$newUser = new User();
$newUser->id = Str::uuid();
$newUser->save();Or, you can automate this by adding a model event in the boot method:
public static function boot() {
parent::boot();
static::creating(function ($model) {
$model->id = Str::uuid();
});
}Step 4: Solving Sanctum Issues
If you’re using Sanctum for API authentication, you may encounter constraint errors due to its default use of integer-based foreign keys. To fix this, create a new migration to modify the tokenable_id column to support UUIDs:
Modify the Migration:
$table->foreignUuid('tokenable_id')->change();
$table->uuid('id')->primary()->change();Create a Custom Personal Access Token Model
use Laravel\Sanctum\PersonalAccessToken as SanctumPersonalAccessToken;
class PersonalAccessToken extends SanctumPersonalAccessToken {
// Customize the model as needed
}Register the Custom Model:
Use Sanctum::usePersonalAccessTokenModel() in AppServiceProvider to tell Laravel to use your custom model.
Conclusion
Using UUIDs in Laravel offers many advantages, especially for applications that require global uniqueness and enhanced security. By modifying your migrations, models, and handling potential issues with third-party packages like Sanctum, you can effectively integrate UUIDs into your Laravel project. Remember, there’s always room for optimization — so share your methods or improvements in the comments!
Have you implemented UUIDs differently or found a more efficient way? Let me know in the comments, and if you’re looking for more Laravel tips, subscribe to our newsletter!
I hope you enjoyed this post. Feel free to clap this article (👏) and subscribe to my Medium newsletter for more.
👋 I offer tech consulting services for companies that need help with their Laravel applications. I can assist with upgrades, refactoring, testing, new features, or building new apps. Feel free to contact me through LinkedIn, or you can find my email on my GitHub profile.




