marshmallow/nova-tags-field
A Laravel Nova tags field for attaching multiple tags to resources, with a searchable dropdown and tag management in the Nova admin panel. Simplifies many-to-many tagging for models like posts or projects while keeping editing fast and intuitive.
Architecture fit
This is not a general Laravel package — it is a Laravel Nova field, and it only produces value inside a Nova admin panel, which is itself a paid, per-site licensed product. If Nova is not already in the stack, the integration cost is not the package, it is the Nova license. Where Nova is present, the fit is narrow but clean: the field extends Laravel\Nova\Fields\Field, ships a compiled Vue component in dist/, and is dropped into a resource's fields() array. It deliberately opts out of Eloquent relationships — tags live in one plain column, so there is no pivot table, no tag entity, no per-tag metadata, and no whereHas. That is a defensible design for free-form labels on low-cardinality admin resources, and an indefensible one the moment anyone asks to rename a tag globally, count tag usage, or permission a tag.
Integration feasibility
Trivially feasible: one composer require, one migration adding a string or text column, one line in the resource. No queue workers, no external services, no config surface worth mentioning. The effort is an afternoon; the risk is entirely lifecycle, not integration.
Technical risk
where('tags', 'like', '%foo%'), which matches substrings (foo hits foobar) and cannot use a B-tree index. Wrong rows surfacing in an admin filter is an operator-visible correctness bug, not a performance nit.Key questions
composer.json constraints on laravel/nova, Laravel, and PHP — does it support Nova v4/v5 at all?dist/ committed and in sync with src/, and can we rebuild it, or are we frozen at the shipped bundle?Filterable/Sortable, and does it validate or sanitize on save?Stack fit Laravel + Nova only. Prerequisites to verify before committing: Nova major version, PHP 8.x compatibility, and a working Node build chain if we ever need to rebuild the field's Vue component. The integration surface is a service provider plus Composer autoload, so it composes cleanly with existing resources and does not constrain application architecture.
Migration path
Add a nullable tags column with a sensible length ceiling. If migrating off an existing tag pivot, treat this as explicitly one-way and lossy: tag IDs, creation timestamps, and usage counts do not survive the move, and any tag-management UI in place becomes a product regression. Write the reverse migration plan before starting — going back to a pivot means parsing a free-form column whose delimiter state is unknown and unenforced.
Compatibility
Pin an exact version and commit SHA via a VCS repository entry, since archived packages never receive constraint updates. Confirm Nova asset publishing and cache invalidation (nova:publish) works for this field; a stale compiled bundle after a Nova upgrade is the single most common failure for third-party fields. Treat any Nova major bump as a scheduled compatibility project, not a routine dependency update.
Sequencing
packages/ or a private registry, tag a SHA, and add a smoke test that mounts the field and round-trips a value.Maintenance Effective maintenance ownership transfers 100% to us on adoption. The compensating factor is that the surface is genuinely small — one field class and one Vue component — so a fork-and-vendor strategy is cheap and materially safer than a live dependency on an archived repository. Budget a named owner and a standing checklist item for every Nova major upgrade.
Support None. No issue triage, no CVE response, no upstream fixes. Debugging means reading the source. Accept this only under the explicit assumption that the code is now ours.
Scaling
Single-column tags do not scale to tag-centric features. Faceted search, tag counts, rename/merge, and per-tag permissions all degrade into table scans or offline reconciliation jobs. Past roughly 10^5 rows, admin filtering on LIKE '%x%' becomes noticeably slow; the escape hatches are MySQL full-text or an indexed generated column, or Postgres GIN over JSON/array — and the package's storage format likely forecloses the latter. There is also a concurrency failure the pivot model avoids: two editors of the same resource perform read-modify-write on the entire column, so one set of tags is silently lost.
Failure modes
dist/ after any rebuild → UI behaviour drifts from source.Ramp-up Near-zero for any developer who has written a Nova resource field. Non-trivial for downstream consumers: analytics and integrations must parse free text because there is no canonical tag list to join against. Product and support carry the real cost — taxonomy drift ("laravel" vs "Laravel") appears as user-visible inconsistency, so a normalization convention (lowercase, trimmed, delimiter-free) must be specified up front rather than discovered later.
Verdict: adopt only as vendored, owned code inside an existing Nova installation, and only for peripheral labelling use cases. Do not make it a live dependency, and do not build any filtering, reporting, or tag-management feature on top of it.
How can I help you explore Laravel packages today?