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 Nova Uuid Support Laravel Package

madewithlove/laravel-nova-uuid-support

Adds UUID primary key support to Laravel Nova, letting resources work with UUID-backed Eloquent models instead of integer IDs. Helps Nova fields, relationships, and search behave correctly when your app uses UUIDs.

View on GitHub
Deep Wiki
Context7

Getting Started

This package is glue, not a framework. It exists because Nova assumes integer primary keys in several places — the ID field defaults to a number, BelongsTo/MorphTo searchable fields occasionally coerce keys, and route resolution expects a numeric resourceId. The package teaches those pieces to respect a model whose getKeyType() is string (UUID, ULID, or any opaque string).

Minimal install:

composer require madewithlove/laravel-nova-uuid-support

There is nothing to publish and no config file to touch. The day-to-day work is a trait on the model plus a one-line change in each resource.

First use case — a User model with a UUID id:

// app/Models/User.php
use Illuminate\Database\Eloquent\Concerns\HasUuids; // Laravel side: generates UUIDs
use Illuminate\Database\Eloquent\Model;
use Madewithlove\LaravelNovaUuidSupport\HasUuidPrimaryKey;

class User extends Model
{
    use HasUuids;
    use HasUuidPrimaryKey; // Nova side: tells Nova how to read/route the key
}
// app/Nova/UserResource.php
public function fields(NovaRequest $request): array
{
    return [
        ID::make()->asText()->sortable(), // critical: keep it a string
        Text::make('Name')->sortable(),
        // ...
    ];
}

Smoke test, in this order: index page (does the ID render fully?), detail page (does the route resolve?), create (does it save?), a BelongsTo picker (does search find records?), global search, then attach/detach on a BelongsToMany.

If your Nova version prefers the trait on the resource instead of the model, the README is the source of truth — verify against the src/ directory before wiring it into more than one resource.

Implementation Patterns

One trait per UUID model, not blanket-applied. Only add the trait to models whose $keyType is string and $incrementing is false. In a mixed app (users UUID, posts auto-increment), this separation is what keeps Nova's intval/Number path intact for integer models.

Relationships carry the key type through the foreign key, not the resource. A BelongsTo::make('Owner', 'owner', UserResource::class)->searchable() works because the related model's key type is string; the parent resource's key type is irrelevant. This means you can have an integer-keyed Post that BelongsTo a UUID-keyed User with no special configuration — just make sure both resources have consistent searchableColumns.

Global search needs explicit columns. $search on the model is a list of column names, and Nova will where like across them regardless of type. Keep id out of $search — lexicographic UUID matches are useless and confusing in the search dropdown.

Route binding is the quiet dependency. Nova resolves {resource}/{resourceId} through resolveRouteBinding, so keep getRouteKeyName() returning 'id'. If you see 404s on detail pages, check for a global Route::pattern('resourceId', '[0-9]+') or a Resource::resolveRouteBinding override in a base resource class.

Actions, Lenses, and Metrics operate on getKey() and generally work unchanged — the failure mode is your own action code casting to int ((int) $model->getKey()). Audit custom actions before shipping.

MorphTo is where things bite. A MorphTo that can point at both an integer-keyed and a UUID-keyed model will render fine but can misbehave in searchable mode. Test each morph target explicitly; if it's a problem, split into two MorphTo fields with ->types([...]) restricted to UUID models.

Testing. Use Laravel's HasUuids on the model and factories; Nova's resource classes are mostly stateless helpers, so a feature test that hits /nova-api/users and asserts a 200 with the UUID in the response body is enough to catch regressions on Nova upgrades.

Gotchas and Tips

Pin and re-test on every Nova upgrade. The last release was 2024-09-16. Nova 4 → 5 changed several field internals; the package patches around them, so a Nova bump is a real regression risk. Add it to your upgrade checklist — "does the UUID resource index/detail still load?"

ID::make() alone is not enough. Without ->asText() the field renders through Number, and long UUIDs truncate or display as 0. Use ->asText(), or swap in a plain Text::make('ID', 'id')->sortable() if you want to avoid the ID field entirely.

Sorting by a UUID is lexicographic, not chronological. Your default $orderBy on the resource should be created_at (or a sequence/timestamp column), not id. Otherwise pagination looks random to users.

Verify the trait actually applied. If relationships misbehave, run in Tinker:

$u = new App\Models\User;
dump($u->getKeyType(), $u->getIncrementing(), $u->getKeyName());

Expected: "string", false, "id". If getIncrementing() is still true, the UUID trait and the package trait are fighting — check model $incrementing and $keyType properties too, they take precedence over traits in some combinations.

BelongsTo "show create" button. The inline create modal for a related resource works, but the created record's ID must be returned in the response. If the package is misapplied, you'll see "record created" but the field stays blank — that's the symptom of a string key being dropped from the JSON payload.

Pivot actions and Detach rely on IDs round-tripping as strings. If Detach sends empty resources, check that your BelongsToMany field isn't using ->fields(fn () => [ID::make()->asNumber()]) inside a pivot block.

Don't stack UUID packages. If you're on Laravel 9+, HasUuids handles generation; this package only handles Nova-side presentation and resolution. Pulling in webpatser/laravel-uuid or a third Nova UUID plugin on top tends to produce conflicting resolveUsing callbacks.

Extension point — resource-level override. If you need finer control than the trait provides, override searchableColumns() on the Nova resource (returning ['id', 'name', 'email'] explicitly) rather than relying on Nova's inference. That's the lowest-friction escape hatch when the package lags behind a Nova release.

Queues and caches are unaffected. SerializesModels serializes $id as whatever type it is, and cache keys built from UUIDs work fine — no special handling needed.

Debugging checklist when a UUID resource breaks after a deploy: (1) php artisan nova:publish — no; (2) php artisan optimize:clear — Nova caches resource discovery; (3) confirm the trait is in the use block and the class actually implements it (IDE auto-imports occasionally alias the wrong class); (4) Log::info((new UserResource($user))->serializeForIndex(new NovaRequest)) to see what the API is emitting.

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.
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels