Skip to content
100% in your browser. Nothing you paste is uploaded — all processing runs locally. Read more →

Generating UUIDs in PHP

On this page
  1. Quick start with ramsey/uuid
  2. Parsing
  3. Symfony alternative: symfony/uid
  4. Laravel
  5. Symfony / Doctrine ORM
  6. Database storage
  7. JSON serialization
  8. Validation in HTTP routes
  9. Performance
  10. Common pitfalls
  11. Cheat sheet
  12. Try the tools

PHP has no built-in UUID functions in the core language. The community uses one of two libraries: ramsey/uuid (the de facto standard) or symfony/uid (newer, leaner, part of Symfony 5.2+).

Quick start with ramsey/uuid

composer require ramsey/uuid
use Ramsey\Uuid\Uuid;

$id = Uuid::uuid4();                                    // v4 random
$v7 = Uuid::uuid7();                                    // time-ordered (4.7+)
$v5 = Uuid::uuid5(Uuid::NAMESPACE_URL, 'https://example.com/users/42');

echo $id->toString();                                   // canonical
echo (string) $id;                                      // same — implements Stringable
echo $id->getHex();                                     // no hyphens
echo bin2hex($id->getBytes());                          // 32-char hex from 16 bytes

UuidInterface is immutable, comparable, and serializable. Cast to string anywhere a string is expected.

Parsing

use Ramsey\Uuid\Uuid;

$id = Uuid::fromString('0e6f1b8c-2c33-4f1f-9c0b-2a3d4e5f6a7b');
$id = Uuid::fromBytes($binary);
$valid = Uuid::isValid($input);

fromString throws InvalidUuidStringException on invalid input. Use Uuid::isValid() first if you’re not sure.

Symfony alternative: symfony/uid

composer require symfony/uid
use Symfony\Component\Uid\Uuid;
use Symfony\Component\Uid\UuidV4;
use Symfony\Component\Uid\UuidV7;

$v4 = Uuid::v4();
$v7 = Uuid::v7();
$v5 = Uuid::v5(Uuid::NAMESPACE_URL, 'https://example.com');

echo (string) $v7;
echo $v7->toBase32();    // Crockford base32 (ULID-style encoding)
echo $v7->toBase58();    // shorter still

symfony/uid has a smaller surface area and is well-suited if you’re already on the Symfony stack. ramsey/uuid is more battle-tested and has more features (RFC variant detection, custom namespaces, time-precision controls).

Laravel

Laravel ships with first-class UUID support via traits:

use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    use HasUuids;
}

HasUuids (Laravel 9.30+) makes id a UUID column and generates v4 on insert. For v7, add newUniqueId:

class User extends Model
{
    use HasUuids;

    public function newUniqueId(): string
    {
        return (string) \Ramsey\Uuid\Uuid::uuid7();
    }
}

Migration:

Schema::create('users', function (Blueprint $table) {
    $table->uuid('id')->primary();
    $table->string('email')->unique();
    $table->timestamps();
});

Symfony / Doctrine ORM

use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;

#[ORM\Entity]
class User
{
    #[ORM\Id]
    #[ORM\Column(type: UuidType::NAME, unique: true)]
    private Uuid $id;

    public function __construct()
    {
        $this->id = Uuid::v7();
    }
}

For ramsey/uuid + Doctrine, use the ramsey/uuid-doctrine adapter.

Database storage

For PostgreSQL: use uuid (native), 16 bytes.

For MySQL 8+: use BINARY(16) and convert with UUID_TO_BIN / BIN_TO_UUID. Both ramsey/uuid and symfony/uid have helpers for this:

$bytes = $id->getBytes();          // 16 raw bytes — ready for BINARY(16)
$id = Uuid::fromBytes($bytes);     // round-trip

Don’t store as VARCHAR(36) — see SQL UUID.

JSON serialization

$id = Uuid::uuid7();
echo json_encode(['id' => $id]);
// {"id":"01928a47-3b30-7c5e-9d1a-f0b8c4a7e923"}

Both libraries implement JsonSerializable. The default form is canonical hyphenated.

Validation in HTTP routes

Laravel:

Route::get('/users/{id}', function (string $id) {
    abort_if(!\Ramsey\Uuid\Uuid::isValid($id), 400);
    // ...
})->where('id', '[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}');

The where constraint validates at the routing layer — invalid UUIDs return 404 before your handler runs.

Symfony:

#[Route('/users/{id}', requirements: ['id' => Requirement::UUID])]
public function show(Uuid $id): Response
{
    // $id is already a Uuid instance, validated
}

Performance

ramsey/uuid is sufficient for typical web throughput. If UUID generation shows up in a profile (rare), symfony/uid is somewhat faster, and Rust extensions like php-ext-ramsey-uuid can give a 10× boost — usually not worth the dependency.

Common pitfalls

Cheat sheet

GoalCode (ramsey/uuid)
RandomUuid::uuid4()
Time-orderedUuid::uuid7()
DeterministicUuid::uuid5(ns, name)
ParseUuid::fromString($s)
ValidateUuid::isValid($s)
Bytes for DB$id->getBytes()

Try the tools