yaeykay's avatar

Laravel UUID

I've read a post about UUID here at Laracasts and it was a year since it was posted.

I also notice the new $this->uuid('id') in the Laravel Docs.

Is there a tutorial about how to use the new $this->uuid('id')?

Thank you

0 likes
5 replies
martinbean's avatar
Level 80

@Piso All $this->uuid('id') does is create a UUID column in your database table. You’ll still need to generate UUIDs in your application. The https://github.com/ramsey/uuid package seems to be the de facto one for generating UUIDs in PHP applications.

3 likes
min-mahatara's avatar

Note: I used ChatGPT to help structure parts of this explanation, but the approach described is from my actual production experience.

Laravel 12.x supports UUIDv7 out of the box (and Laravel 11.x introduced it). However, if you want to use both UUID7 and ULID together on the same model, you'll need a custom solution.

✅ Internal vs. External Identifiers

Using UUIDv7 for primary keys (e.g., id) is an excellent choice—especially for scalable applications. UUIDs are globally unique and make tasks like data merging and system interoperability much safer by minimizing the risk of key collisions.

One of the key advantages of using UUIDs as internal identifiers is that you can perform direct database operations without relying solely on APIs. This encourages cleaner, more decoupled API design.

However, UUIDs (especially v7) are long and not user-friendly. Therefore, I strongly recommend not exposing UUIDs to end users. Instead, use ULIDs for public-facing IDs.

For example:

  • Use id (UUIDv7) internally for primary keys, foreign keys, and unique constraints.
  • Use public_id (ULID) externally in URLs, APIs, and UI displays.

This separation protects internal infrastructure and keeps your system's internals abstracted from external consumers.

🛠 CRUD Operations and Routing

Always expose and interact with the public_id for all CRUD operations. This adds a slight abstraction layer but helps shield internal identifiers and improves system design.

Laravel allows you to customize route model binding to use public_id:

public function getRouteKeyName(): string
{
    return 'public_id';
}

⚖️ Performance Considerations

It's true that UUIDs and ULIDs can be slightly slower than auto-incrementing integers due to their size and index performance. However, the benefits—global uniqueness, scalability, and flexibility—far outweigh these drawbacks, especially for distributed systems.

UUIDv7 offers the additional benefit of lexical sortability. Because it encodes a timestamp in milliseconds, newly generated UUIDs are naturally ordered. This improves index locality and query performance compared to UUIDv4.

🔄 Data Portability

Another major benefit of UUIDs: they're ideal for syncing data across environments or services. Since UUIDs are unique across systems, there's very little risk of collision when importing or migrating data.


✅ Recommended Strategy

  • Internal IDs (id, FK, PK, UK): Use UUIDv7. Never expose.
  • External IDs (public_id): Use ULID. Always expose.

🧩 Custom Trait: HasUuidsAndPublicId

Since Laravel does not currently support using both HasUuids and HasUlids traits together in a single model, you can define a custom trait to achieve this:

Use this trait on your models:

class User extends Model
{
    use HasUuidsAndPublicId;

    protected $table = 'users';
}

⚠️ Note: Trying to use both HasUuids and HasUlids traits simultaneously, like this:

use HasUuids, HasUlids;

will not work, as Laravel does not currently support combining both traits on the same model.


Final Thoughts

For scalable Laravel applications:

  • Use UUIDv7 for internal keys.
  • Use ULIDs for external identifiers.
  • Encapsulate this logic in custom traits like HasUuidsAndPublicId.

This strategy balances performance, security, and maintainability, and is already adopted by many large-scale systems.

Please or to participate in this conversation.