Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Eloquent Uuid Laravel Package

eig/eloquent-uuid

A Laravel package that lets Eloquent models use UUID primary keys instead of auto-incrementing integers. Drop it into existing models to generate unique, non-sequential IDs automatically for safer, distributed-friendly records.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. The package is a single Eloquent trait (~30–40 lines) that hooks the creating model event, assigns a UUID to the primary key, and flips $incrementing = false / $keyType = 'string'. That is the idiomatic Laravel extension point — it composes into any model without touching schema, routing, or serialization, and it keeps route-model binding working because the PK is the route key. From a product-architecture standpoint the package does not decide anything meaningful: it implements a decision (opaque public identifiers) that TPMs must make anyway. Its scope is narrow by design, and it explicitly does not address storage format (char(36) vs binary(16)), index locality, ordered IDs (ULID/UUIDv7), or database-level defaults. Those remain separate architecture calls.

Integration feasibility. Constrained. Release 3.0.0 pins PHP 8.0+, illuminate/* 9.x, and a transitive runtime dependency on eig/UUID 2.5.x. On Laravel 10/11, Composer either refuses resolution or installs something never tested against the framework — treat that as disqualifying, not as "probably fine." The addressable window is narrow: Laravel 9 is exactly the baseline where Laravel already ships HasUuids and HasUlids in Illuminate\Database\Eloquent\Concerns. The package's residual value is trait ergonomics and a forkable reference implementation, not capability.

Technical risk. High relative to the value delivered:

  • Abandonment risk: last release December 2022, 59 stars, 0 dependents, single maintainer.
  • Dependency chain: 3.0.0 adds a second package from the same maintainer — two dependents to track on every framework bump, with no downstream population to surface breakage before we do.
  • Framework ceiling below EOL: Laravel 9 left security support in February 2024. Adopting this package means adopting an unsupported framework floor.
  • Redundancy hazard: combining this trait with native HasUuids/HasUlids produces two creating hooks racing on id and competing $keyType assignments. Silent, hard-to-diagnose corruption of the model contract.
  • Correctness gap: Model::insert(), upsert(), query-builder writes, raw seeders, and raw SQL bypass creating entirely — producing NULL keys and broken foreign keys. The #1 silent failure mode.
  • Non-monotonic v4: random UUIDs cause B-tree page splits and index bloat on write-heavy InnoDB tables. The package does not solve this.

The 0.595 score and thin adoption signal should be read as insufficient evidence of quality, not as evidence of poor code — but for a TPM, insufficient evidence plus an abandoned maintainer plus an EOL framework is a decision, not a question.

Key questions to resolve before approving:

  1. Are we on Laravel 9 today, and is a major framework upgrade in the next 12–18 months? (If yes, this is disqualified.)
  2. Is this a greenfield bounded context or a retrofit onto populated tables? (Retrofit is effectively prohibitive — every FK dropped and rebuilt.)
  3. Do we need ordered IDs for write-heavy tables? (Then ULID/UUIDv7, not this.)
  4. Does any write path use insert()/upsert()/query-builder instead of Model::create? (Then the trait will silently emit NULL keys.)
  5. Is char(36) acceptable on every secondary index and FK, or do we need binary(16) casting?
  6. Who owns the fork if the maintainer disappears? At ~40 lines, forking is cheap — but it must be a named owner, not an implicit one.

Integration Approach

Stack fit. Only consider under a hard constraint: Laravel 9.x / PHP 8.0+, existing investment in eig/UUID 2.x, greenfield bounded context, single id primary key, all writes through Eloquent. Apply it deliberately to 3–5 truly public-facing models (orders, invoices, api_tokens, share_links, webhooks) — not grep-and-apply across the codebase. Join tables, audit logs, jobs, and cache should keep integer PKs.

Recommended default: bypass the package. For any target other than the narrow constraint above, the honest answer is:

  • Laravel 10/11 → native HasUuids (or HasUlids for ordered, index-friendly IDs). Zero net-new dependencies, covered by framework tests, patched with framework releases.
  • Existing app with populated tables → keep the integer PK, add a uuid column with getRouteKeyName() returning 'uuid', and generate via Str::uuid() in a booted() hook. This avoids FK rebuilds entirely.
  • Need binary(16), non-id PK, or UUID on a non-PK column → fork the ~40-line trait into App\Concerns. This simultaneously removes the eig/UUID dependency, the Laravel 9 ceiling, and the maintainer risk. Usually the right call.

Compatibility controls if adopted. Pin exactly ("3.0.*"), add both eig/eloquent-uuid and eig/UUID to the dependency inventory, and verify behavior against 3.0.0 — not against 2.x-era guidance. The 2.x → 3.0 jump changed PHP/Laravel floors, the transitive dependency, and possibly trait name and key-type handling. Copy the trait FQN from the vendor directory, not from a blog post.

Sequencing.

  1. Decision first, package second. Resolve the primary-key question before schema freeze — this is a one-way door for new bounded contexts. Retrofitting UUID PKs later means dropping every FK and rewriting every referencing row.
  2. Spike validation. Use the package in a throwaway prototype or tinker session to validate the UUID-PK decision cheaply: create a model, confirm getKeyType() === 'string' and getIncrementing() === false, confirm relations and JSON serialization behave.
  3. Write the ADR. Record which models get UUIDs and why, and note explicitly that three lines of framework behavior are hidden behind use HasUuid;. Without this, the next contributor applies it everywhere.
  4. Land the roadmap item at the same time as adoption. Migrate to native HasUuids or fork the trait — scheduled, not "later." Treating the Laravel 9 ceiling as a forcing function is the only responsible condition of adoption.
  5. Verify before scaling. Assert getIncrementing() and getKeyType() in the test suite, not just the ID format. A framework or eig/UUID bump can break those without breaking the ID itself.

Operational Impact

Maintenance. Two packages from one maintainer, last shipped December 2022, zero dependents to act as a canary. Every Laravel major bump becomes a manual compatibility investigation against an unsupported library, with no upstream test suite to lean on. The realistic maintenance posture is "vendor or fork it," which converts a dependency decision into an ownership commitment — someone on the team must own the ~40 lines.

Support. Effectively none. No community, no security response path, no release cadence. The source of truth is the vendor directory. This is a meaningful operational cost not visible in the adoption cost: debugging falls to whoever can read the trait, and that knowledge is tribal unless documented in the ADR.

Scaling. Two distinct concerns:

  • Storage and index cost. $table->uuid() maps to char(36) on MySQL — 36 bytes on every secondary index and every FK, amplified across join tables. binary(16) is the answer if write volume or index size matters, but it requires cast handling at the model layer and must be decided before schema freeze.
  • Write throughput. Random v4 is non-monotonic on InnoDB, causing B-tree page-split churn and index bloat on write-heavy tables. For high-insert workloads (event logs, token issuance), HasUlids or UUIDv7 is the pragmatic move. The package does not solve ordering locality; adopting it for a write-heavy table is a scaling decision made by accident.

Failure modes to instrument and guard against:

  • Silent NULL keys on bulk paths. Model::insert(), upsert(), query-builder seeders, and raw SQL bypass the creating event. Mitigation: a DB-level default where supported, plus a Str::uuid() fallback inside import and seeder paths, plus a schema NOT NULL constraint to fail loudly rather than propagate broken FKs.
  • Trait did not boot. Applying the trait via a parent class rather than inside the model body, or a parent model shadowing it, leaves incrementing = true. Mitigation: a debug assertion (getIncrementing(), getKeyType(), getKeyName(), toArray()['id']) in the test suite for every model that uses it.
  • Double-hook collision. Mixing with native HasUuids/HasUlids produces competing creating hooks and key-type assignments. Mitigation: an explicit "one UUID mechanism per model" rule, enforced in code review.
  • Client-generated ID overwrite. If the trait unconditionally overwrites a pre-set key, offline-first ingestion paths corrupt client-assigned IDs. Mitigation: confirm the boot method guards on if (! $model->getKey()), or bypass the trait on that path.
  • Binary value clobbering. If the trait ignores pre-set binary keys, binary(16) PKs break silently.

Ramp-up. Low in absolute terms — the trait is readable in one sitting and forkable in an hour. The real onboarding cost is the surrounding knowledge: why only three models carry it, why bulk writes need a fallback, why char(36) was chosen, and what the exit plan looks like. That cost is paid once if the ADR exists and repeatedly if it doesn't. Budget the ADR and a short test assertion as part of the integration, not as follow-up work.

Bottom line for roadmap planning. This package does not buy capability — it buys a small amount of typing in a configuration where Laravel already provides the capability natively, at the cost of an unsupported framework floor and two unattended dependencies. The valuable decision it supports (opaque public identifiers) should be made on product and architecture grounds, then implemented with native HasUuids/HasUlids or a five-line in-house trait. Approve only as a validated spike on a greenfield Laravel 9 context, with a fork-or-native migration item on the roadmap from day one.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast