alesitom / hybrid-id
Compact, time-sortable unique ID generator for PHP. Drop-in UUID/ULID alternative with base62 encoding, Stripe-style prefixes, and configurable entropy profiles.
Requires
- php: >=8.3
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.94
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^11.0
Suggests
- alesitom/hybrid-id-doctrine: Doctrine integration — DBAL type and ORM ID generator
- alesitom/hybrid-id-laravel: Laravel integration — Eloquent trait, service provider, and config
- vlucas/phpdotenv: Load HYBRID_ID_PROFILE and HYBRID_ID_NODE from .env files (^5.6)
- dev-main
- v4.3.0
- v4.2.0
- v4.1.2
- v4.1.1
- v4.1.0
- v4.0.0
- v3.2.2
- v3.2.1
- v3.2.0
- v3.1.1
- v3.1.0
- v3.0.0
- v2.2.0
- v2.1.0
- v2.0.1
- v2.0.0
- v1.4.1
- v1.4.0
- v1.3.0
- v1.2.0
- v1.1.2
- v1.1.1
- v1.1.0
- v1.0.0
- dev-dependabot/github_actions/codecov/codecov-action-5.5.2
- dev-ci/quality-checks
- dev-docs/v4.2.0-changelog
- dev-test/v4.2.0-benchmarks
- dev-fix/v4.2.0-code-review
- dev-feature/v4.2.0-enhancements
- dev-refactor/v4.2.0-code-quality
- dev-chore/gitignore-tmp
- dev-fix/v4.1.2
- dev-feat/v4.1.1
- dev-fix/v4.0.0-review
- dev-docs/readme-restructure
- dev-feat/v4.0.0
- dev-chore/php85-ci
- dev-chore/packagist-seo
- dev-feat/v3.2.0-features
- dev-fix/v3.1.1-issues-95-98
- dev-fix/v3.1.0-issues-85-90
- dev-feat/v3.0.0-interface-cli
- dev-feat/v2.2.0-features
- dev-fix/issues-70-76
- dev-fix/issues-60-61-65-67
- dev-fix/issues-59-62-63-64
- dev-docs/v2-readme
- dev-feat/v2-custom-profiles
- dev-feat/v2-compare-method
- dev-feat/v2-random-bytes-optimization
- dev-feat/v2-instance-api
- dev-feat/v2-prefix-support
- dev-fix/packagist-auth
- dev-fix/v1.4.0-polish
- dev-fix/v1.3.0-refinements
- dev-fix/v1.2.0-hardening
- dev-fix/packagist-auto-update
- dev-fix/drop-php82
- dev-fix/v1.1.0-improvements
This package is auto-updated.
Last update: 2026-02-21 18:12:31 UTC
README
Compact, time-sortable unique identifiers for PHP
A space-efficient alternative to UUID with configurable entropy profiles, Stripe-style prefixes, and an instance-based API. Generate chronologically sortable, URL-safe identifiers 33-56% smaller than canonical UUIDs — with zero dependencies.
Why HybridId?
| Feature | HybridId | TypeID | KSUID | UUIDv7 | NanoID | CUID2 |
|---|---|---|---|---|---|---|
| Length | 16-24 chars | 26 chars | 27 chars | 36 chars | 21 chars | 24 chars |
| Configurable size | Yes | No | No | No | No | No |
| Type prefixes | Yes | Yes | No | No | No | No |
| Time-sortable | Yes | Yes | Yes | Yes | No | No |
| Metadata extraction | Full | Partial | Partial | Partial | None | None |
| Zero dependencies | Yes | Varies | Varies | Yes | Varies | Varies |
| Range queries | Yes | No | No | No | No | No |
| Multi-node safe | Yes | Yes | No | Yes | N/A | N/A |
| Random entropy | 47.6 - 83.4+ bits | ~80 bits | 128 bits | 74 bits | ~126 bits | ~120 bits |
Installation
composer require alesitom/hybrid-id
Requires PHP 8.3, 8.4, or 8.5 (64-bit). No external dependencies.
Quick Start
use HybridId\HybridIdGenerator; $gen = new HybridIdGenerator(node: 'A1'); $id = $gen->generate(); // 0VBFDQz4A1Rtntu09sbf $id = $gen->generate('usr'); // usr_0VBFDQz4A1Rtntu09sbf $id = $gen->compact('log'); // log_0VBFDQz6xK9mLp2w $id = $gen->extended('txn'); // txn_0VBFDQz7A1pBKVwwn2xiF0
Profiles
Three built-in profiles with different size/entropy tradeoffs:
| Profile | Length | Structure | Random entropy | Use case |
|---|---|---|---|---|
compact |
16 | 8ts + 8rand | 47.6 bits | Internal PKs, low-scale apps |
standard |
20 | 8ts + 2node + 10rand | 59.5 bits | General purpose (default) |
extended |
24 | 8ts + 2node + 14rand | 83.4 bits | High-scale, public-facing IDs |
Standard / Extended: Compact (no node):
0VBFDQz4 A1 Rtntu09sbf 0VBFDQz4 xK9mLp2w
|______| |_| |_________| |______| |________|
ts node random ts random
- ts (8 chars): Millisecond timestamp in base62. Enables chronological sorting.
- node (2 chars, standard/extended): Server/process identifier. Prevents cross-node collisions.
- rand (variable): Cryptographically secure random bytes via
random_bytes().
Custom profiles are available via ProfileRegistry — see API Reference.
Configuration
use HybridId\HybridIdGenerator; // Standard profile with explicit node (recommended for production) $gen = new HybridIdGenerator(node: 'A1'); // Explicit profile $gen = new HybridIdGenerator(profile: 'extended', node: 'A1'); // Compact — no node needed $gen = new HybridIdGenerator(profile: 'compact'); // From environment variables (HYBRID_ID_PROFILE, HYBRID_ID_NODE, HYBRID_ID_BLIND, HYBRID_ID_BLIND_SECRET) $gen = HybridIdGenerator::fromEnv();
By default, standard and extended profiles require an explicit node to prevent accidental collisions in production. Pass requireExplicitNode: false for local development.
Prefixes
Stripe-style prefixes make IDs self-documenting:
$gen->generate('usr'); // usr_0VBFDQz4A1Rtntu09sbf $gen->generate('ord'); // ord_0VBFDQz5A1xiF0G9pBKV
Rules: 1-8 chars, lowercase alphanumeric, starts with a letter. All extraction and validation methods handle prefixed IDs transparently.
Database
Column sizing
| Profile | No prefix | With prefix (max 3) | With prefix (max 8) |
|---|---|---|---|
compact |
CHAR(16) |
VARCHAR(20) |
VARCHAR(25) |
standard |
CHAR(20) |
VARCHAR(24) |
VARCHAR(29) |
extended |
CHAR(24) |
VARCHAR(28) |
VARCHAR(33) |
Collation (MySQL/MariaDB)
Base62 uses mixed case (A != a). You must use ascii_bin or utf8mb4_bin collation — the default utf8mb4_0900_ai_ci will silently break uniqueness and sort order.
CREATE TABLE users ( id CHAR(20) COLLATE ascii_bin NOT NULL PRIMARY KEY, ... );
PostgreSQL and SQLite are case-sensitive by default — no special collation needed.
Storage efficiency
| Format | Size | Savings vs UUID |
|---|---|---|
| UUID (canonical) | CHAR(36) | — |
| ULID | CHAR(26) | 28% |
| TypeID | VARCHAR(34) | 6% |
| HybridId compact | CHAR(16) | 56% |
| HybridId standard | CHAR(20) | 44% |
| HybridId extended | CHAR(24) | 33% |
Smaller primary keys improve B-tree index density and reduce page splits. Time-sorted layout eliminates the random-insert penalty of UUID v4. See Database Guide for time-range queries, NoSQL patterns, and migration strategies.
Security
Not for secrets. Do NOT use HybridId for security tokens, session IDs, API keys, or password resets. The timestamp is predictable — use random_bytes() with 128+ bits for those.
Standards alignment:
- RFC 9562: UUIDv8 compliant via
UuidConverter::toUUIDv8() - CSPRNG:
random_bytes()backed by OS-level cryptographic random - RFC 3986: URL-safe base62, no percent-encoding needed
- Rejection sampling eliminates modulo bias (NIST SP 800-90A aligned)
What HybridId is NOT: not OWASP ASVS V2.6 compliant, not constant-time in validation, timestamps are predictable by design (same as UUIDv7).
Blind Mode
HMAC-hashes the timestamp and node with a per-instance secret, making creation time unextractable. Same length and format — an observer cannot tell if an ID is blind.
$gen = new HybridIdGenerator(node: 'A1', blind: true); $id = $gen->generate('usr'); // usr_<opaque20chars>
See Blind Mode for details on what works, what changes, and when to use it.
UUID Interoperability
Convert between HybridId and RFC 9562 UUIDs:
| Method | Lossless | Notes |
|---|---|---|
UuidConverter::toUUIDv8() / fromUUIDv8() |
Yes | Profile auto-detected on decode |
UuidConverter::toUUIDv7() / fromUUIDv7() |
No | Timestamp-preserving, needs profile hint |
UuidConverter::toUUIDv4Format() / fromUUIDv4Format() |
No | Lossy, NOT a true UUIDv4 |
Compact and standard profiles only. Prefixed IDs are rejected — strip prefix first.
See UUID Interoperability for full examples and compatibility matrix.
Framework Integrations
| Package | Framework | Install |
|---|---|---|
| hybrid-id-laravel | Laravel 11/12 | composer require alesitom/hybrid-id-laravel |
| hybrid-id-doctrine | Doctrine DBAL 4 / ORM 3 | composer require alesitom/hybrid-id-doctrine |
See Dependency Injection & Testing for IdGenerator interface, DI wiring, and framework examples.
Requirements
- PHP 8.3, 8.4, or 8.5 (64-bit)
- No external dependencies
Learn More
| Topic | Link |
|---|---|
| Full API (validation, parsing, metadata, sorting, custom profiles) | docs/api-reference.md |
| UUID conversion (v8, v7, v4-format) | docs/uuid-interoperability.md |
| Database (time-range queries, NoSQL, migration from UUID) | docs/database.md |
| Blind mode (HMAC-hashed timestamps) | docs/blind-mode.md |
| CLI reference | docs/cli.md |
| Dependency injection & testing | docs/dependency-injection.md |
| Internals (clock drift, concurrency, design decisions) | docs/internals.md |
| Upgrading (v1 → v2 → v3 → v4) | UPGRADING.md |
| Changelog | CHANGELOG.md |
License
MIT