benjacho/belongs-to-many-field
Benjacho's BelongsToMany field for Laravel Nova adds a searchable modal for attaching and detaching related models, supports inline creation, and simplifies managing many-to-many relationships in Nova resources.
Architecture fit
Field subclass, a service provider, publishable config, and a compiled Vue bundle in dist/js. It renders inside Nova resource forms and detail views. It introduces no migrations, no models, no service-layer opinions, and no schema changes — the relationship and pivot tables remain ours.belongsToMany editing. If we are not on Nova, the addressable use case is zero and the evaluation ends there.BelongsToMany pattern forces admins through index → attach → detach → back. Collapsing tag/category/role/catalogue maintenance into one searchable control is a genuine time-on-task reduction, and it is the kind of commodity back-office work that should never consume custom Vue effort.Integration feasibility
composer require benjacho/belongs-to-many-field, then BelongsToManyField::make('Tags', 'tags', Tag::class) in a resource's fields(). No manual provider registration in a standard Nova install.belongsToMany relation with correct pivot foreign keys; withPivot() declared on the Eloquent model if pivot attributes are to be edited; an indexed, human-readable label column on the related table for search.->options([...]) for small fixed or tenant-scoped sets (roles, statuses, curated categories) versus ->label() + ->searchable() for large dynamic tables. Getting this wrong per resource is where most operational risk lands, so it must be a documented, reviewed choice rather than a developer default.singleSelect(), displayAsBadges()/displayAsList(), placeholder(), rules(). Low learning cost, low lock-in.Technical risk
3.0.1-beta, 156 stars, zero reported dependents. Nova has advanced through major versions since; the validated support matrix is almost certainly behind our stack. We should assume we are the integration test.Key questions
searchable() paginate and query server-side, or hydrate the full option set into the browser? What are query counts, payload size, and render time at 10k+ related records?BelongsToMany in the same codebase, enabling per-resource fallback without a revert deploy?Stack fit
BelongsToMany remains the default; this is opt-in per field, per resource.Migration path
fields() array and leave a commented one-line revert to the native field directly beside it. That makes rollback a code review, not an incident.Compatibility
^ ranges. Add a standing line to the Nova upgrade runbook: upgrading Nova requires re-validating this field, re-publishing assets, and re-running the spike checklist.Sequencing
options() vs searchable() decision recorded, the policy/validation review signed off, and per-resource rollback documented.Maintenance
repositories override, release tag) written before it is needed. A fork procedure authored during an incident costs days; authored in advance it costs an afternoon.Support
Scaling
searchable() with an indexed label column, and confirm empirically that the component queries on demand rather than hydrating everything.hideFromIndex() wherever list rendering is unnecessary; it is free, and it removes an entire class of complaint.options() threshold, resources will need migrating to searchable(). Note the trigger threshold in the runbook so the switch is a scheduled task, not a performance incident.Failure modes
Ramp-up
How can I help you explore Laravel packages today?