Articles

Using ULID and UUIDv7 in MySQL as Primary Key With Examples

Using ULID and UUIDv7 in MySQL as Primary Key With Examples

Modern systems increasingly require globally unique identifiers that scale horizontally across services, servers, and regions. Although we use integer primary key in most of the databases, in distributed systems developers think another way of handling primary keys using binary format.

 

 

Two modern alternatives for primary key:

  • ULID (Universally Unique Lexicographically Sortable Identifier)

  • UUIDv7 (a new, time-ordered UUID variant standardized in RFC 9562)

What the ULID and UUID7 offers:

  • Global uniqueness

  • Time-ordered identifiers

  • More index-friendly structure than UUIDv4

  • Compatibility with MySQL’s BINARY(16) storage

 

What is ULID?

ULID is a 128-bit identifier consisting of:

48 bits — timestamp  
80 bits — randomness

ULID Benefits:

  • Sortable by creation time

  • Human-readable (26 characters)

  • Great for Big Data,  Logs, APIs, distributed systems.

Example:

01J0MZF81Z8ZKP9E9F2X1YHVCN

 

What is UUID7?

UUIDv7 is part of the new UUID proposal (RFC 9562):

  • Time-ordered

  • Highly index-friendly

  • Compatible with existing UUID standards.

Example: 

018f24e1-fa4c-7f4b-b497-f5c8d85b1d7a

Example Mysql Table:

The best practice is to store ULID and UUID7  as BINARY(16):

CREATE TABLE users (
    id BINARY(16) PRIMARY KEY,
    email VARCHAR(255) UNIQUE NOT NULL,
    name VARCHAR(255),
    created_at DATETIME(6) NOT NULL
) ENGINE=InnoDB;
CREATE TABLE orders (
    id BINARY(16) PRIMARY KEY,
    user_id BINARY(16) NOT NULL,
    status ENUM('pending','paid','shipped','cancelled') NOT NULL,
    total_amount DECIMAL(10, 2) NOT NULL,
    created_at DATETIME(6) NOT NULL,
    updated_at DATETIME(6),

    INDEX (user_id),
    CONSTRAINT fk_orders_user
        FOREIGN KEY (user_id) REFERENCES users(id)
) ENGINE=InnoDB;

Here i declared the id as Binary(16) and also the user_id column as Binary(16)

BINARY(16) datatype features:

  • Half the size of CHAR(36)

  • Better index performance

  • Saves disk, memory, and IO

 

Example Generating ULID and UUID7 in PHP:

Install Symfony UID library:

composer require symfony/uid
use Symfony\Component\Uid\Ulid;

$ulid = new Ulid();
$binary_ulid = $ulid->toBinary();

$stmt = $pdo->prepare("INSERT INTO users (id, email, created_at) VALUES (?, ?, NOW(6))");
$stmt->execute([$binary_ulid, "user@example.com"]);

For UUID7:

use Symfony\Component\Uid\Uuid;

$uuid7 = Uuid::v7();
$binary = $uuid7->toBinary();

$userId = $binary_ulid;

$stmt = $pdo->prepare("INSERT INTO orders (id, total, user_id, created_at) VALUES (?, ?, ?, NOW(6))");
$stmt->execute([$binary, 199.99, $userId]);

Converting back when reading:

$id = $row['id'];

$ulid = Ulid::fromBinary($id);
$uuid7 = Uuid::fromBinary($id);

echo $ulid;   // readable text form
echo $uuid7;

 

Example Using ULID and UUID7 in Laravel:

Laravel has built-in support for UUIDs, and with a small addition can easily support ULID and UUIDv7.

Migration code:

Schema::create('users', function (Blueprint $table) {
    $table->binary('id')->primary(); // ULID or UUIDv7
    $table->string('email')->unique();
    $table->timestamps(6);
});

To handle automatic generating ID’s in Model:

use Symfony\Component\Uid\Ulid;

class Order extends Model
{
    public $incrementing = false;
    protected $keyType = 'binary';

    protected static function boot()
    {
        parent::boot();

        static::creating(function ($model) {
            if (!$model->id) {
                $model->id = (new Ulid())->toBinary();

                // If using UUID7
                // $model->id = Symfony\Component\Uid\Uuid::v7()->toBinary();
            }
        });
    }
}

Returning IDs as Strings in APIs

write an accessor:

public function getIdAttribute($value)
{
    return Ulid::fromBinary($value);
}

 

0 0 votes
Article Rating

What's your reaction?

Excited
0
Happy
0
Not Sure
0
Confused
0

You may also like

Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments