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

Laravel Eloquent Uuid Slug Laravel Package

khalyomede/laravel-eloquent-uuid-slug

A Laravel package that adds UUID slug support to Eloquent models, automatically generating unique, URL-friendly identifiers for your records so you can reference them in routes and links instead of exposing numeric IDs.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. The package is a thin Eloquent trait that generates a UUID slug and exposes it as the model's route key, so it slots into Laravel's existing trait + implicit route model binding conventions rather than introducing a new abstraction layer. It is additive by design: you keep your integer/UUID primary key and foreign keys intact, and add a secondary slug column used only for public identification and lookup. That keeps blast radius small — no service provider gymnastics, no repository pattern, no change to query semantics beyond getRouteKeyName(). For a product whose only requirement is "don't expose sequential IDs in URLs," this is the minimal viable mechanism.

Integration feasibility. Work is concentrated in three places: a migration adding slug (unique index, eventually NOT NULL), the trait on each target model, and controller/route signatures that switch from Model $model resolved by id to resolution by slug. Existing rows need a backfill. No queue, cache, or external service dependency. A competent Laravel developer can prove this out in under a day.

Technical risk.

  • Maturity signal is weak. 23 stars, 0 dependents, single maintainer. Treat this as "small enough to vendor," not "dependency worth tracking." The code is likely a few dozen lines; the real risk is silent incompatibility with current Laravel (implicit binding, getRouteKeyName, model event boot order) rather than architectural mismatch.
  • Version drift. Package age suggests it targets Laravel 5.x/6.x. Confirm composer.json constraints against our Laravel/PHP floor before planning.
  • Identifier semantics. UUIDv4 strings are non-sequential; as a secondary unique index this is fine, but they fragment indexes if anyone later promotes slug to primary key. Also confirm whether collisions are retried or simply throw.
  • Namespace collision. slug is the same column name used by spatie/laravel-sluggable and similar packages. If we ever want human-readable slugs, this decision pre-empts it.
  • Event bypass. Bulk insert()/upsert() and raw seeding skip model events, so slugs will be absent — a recurring source of production data gaps.

Key questions for the maintainer / spike.

  1. Does it override the primary key or only the route key, and does it write the UUID app-side before insert?
  2. What is the collision-retry behavior, and is the column indexed unique by the package migration or by us?
  3. Which Laravel/PHP versions are in the CI matrix, and is there test coverage for withTrashed, whereHas, and bulk operations?
  4. Is there a config publish step (column name, UUID version), or is it hardcoded?
  5. Does it expose the slug on serialization, or do we control that via API Resources?

Integration Approach

Stack fit. Best suited to a conventional Laravel monolith or JSON API that leans on Eloquent route model binding for public-facing resources — customer portals, shareable links, audit-friendly URLs. It is a poor fit if we already expose UUID primary keys (redundant), or if the identifiers are consumed by partners who expect stable, sortable, human-referenceable IDs.

Migration path. Sequential, reversible, zero-downtime:

  1. Add nullable slug column plus a unique index in a standalone migration.
  2. Backfill in chunks via a queued job or artisan command, generating deterministic UUIDs.
  3. Add NOT NULL constraint and enable the trait per model.
  4. Flip getRouteKeyName() and update controllers, policies, and tests.
  5. Update API documentation and client SDKs; keep id-based routes alive behind a deprecation window.

Because id remains the primary key, rollback is simply disabling the trait and reverting the route signatures — the column can stay dormant.

Compatibility considerations. Verify implicit binding behavior with soft deletes (withTrashed) and nested resources; check that whereHas/with eager loads still key correctly; ensure Laravel Scout indexes the slug if search-powered lookups exist; ensure API Resources emit slug and suppress id so clients don't regress to the old identifier. If Horizon/queues serialize models, confirm route() helper output in queued mailables updates.

Sequencing. Spike and fork-read the source first (>1 hour, resolves the key questions), then migrations/backfill, then per-model rollout starting with the lowest-traffic public resource, then documentation, then deprecation of id routes. Do not bundle this with an unrelated schema release — the backfill and constraint change want a quiet deploy window.

Operational Impact

Maintenance. Effectively zero ongoing maintenance if we accept ownership. Given the dependency profile, I would vendor the trait into app/Models/Concerns and delete the Composer requirement. That converts an unmaintained third-party package into ~40 lines we control, and eliminates the upgrade-blocker risk at the next Laravel major.

Support. No vendor, no SLA, community-only issue tracker with a single maintainer. Internal ownership must be assigned explicitly; otherwise this becomes orphaned infrastructure that nobody understands during an incident.

Scaling. One additional unique-index write per model insert — negligible at our volumes. Read path is a single indexed string lookup, comparable to primary key resolution. Watch storage if we roll this across high-cardinality tables (36 bytes/row plus index); consider binary(16) or UUIDv7 only if the slug becomes a hot join key, which it should not.

Failure modes to design against.

  • Duplicate-key exception on rare collision → wrap creation in retry or assert the package does.
  • Null slug from bulk inserts, seeders, or imports → enforce NOT NULL post-backfill and add a factory state.
  • Silent 404s after partial backfill or when a slug is regenerated → slugs must be immutable; never rotate them, and treat them as permanent public identifiers.
  • Cached URLs, emails, and analytics referencing old slugs → immutability plus a redirect table if rotation is ever required.
  • Route model binding masking bugs as 404s rather than 500s → add explicit tests asserting the resolved key.

Ramp-up. Under a day for a Laravel-fluent engineer, most of it spent on the backfill and route-signature sweep rather than the package itself. Add the trait convention to the team's new-model checklist and document "public identifier = slug, internal = id" in the API style guide so the pattern doesn't drift.

Recommendation. Adopt the pattern, not the dependency: implement the trait in-house, ship the migration and backfill, and revisit only if the public identifier requirement grows into human-readable slugs, at which point spatie/laravel-sluggable is the better-supported choice.

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.
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table
siberfx/flysystem-wasabi
hollyit/token-replace
ippanelcom/laravel-sdk
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