rinvex/laravel-tags
Rinvex Laravel Tags adds flexible tagging to Eloquent models, letting you attach tags and tag types to any model polymorphically. Manage tags, slugs, and relationships easily with a clean API for building searchable, categorized content in Laravel apps.
Architecture fit
rinvex/laravel-tags implements the standard polymorphic tag pattern for Eloquent: a tags table, a taggables pivot (taggable_type, taggable_id, tag_id), and a HasTags trait mixed into any model. That is the correct shape for this problem and maps cleanly onto any Laravel domain model we already own. It also advertises slug generation and translation of tag names out of the box, which is table stakes for any product with multi-locale taxonomy.
The architectural concern is not the pattern, it is the dependency graph. The package builds on rinvex/laravel-support (and, for translations, likely spatie/laravel-translatable — verify in composer.json). That means adopting a 29-star archived package pulls in a second-order dependency from the same vendor as a hard requirement for our core content model. We would be inheriting an unmaintained transitive layer in the middle of our persistence code, which is the hardest place to refactor later.
Integration feasibility
Installation is low-effort and conventional: composer require, publish migrations and config, run migrations, add the trait plus a $taggable / taggable-type registration to each model. A competent Laravel engineer can have a working spike in under a day. There is no service provider complexity, no queue/worker surface, no external service, no runtime infrastructure. Integration cost is genuinely small — which is precisely why the decision should be made on ownership cost, not on effort.
The feasibility blocker is version compatibility. With the repo archived, there is no evidence of support for Laravel 10/11/12 or PHP 8.2+. Treat the declared constraints as stale until proven otherwise, and expect the trait and migration stubs to need patching against current framework conventions (attribute casting, anonymous migration classes, Model::preventLazyLoading, etc.).
Technical risk
spatie/laravel-tags covers the same ground with active maintenance, first-party docs, and broad adoption. Choosing the archived option requires a positive reason, and the description offers none.Key questions
spatie/laravel-tags? If the answer is "translated tag names," confirm whether Spatie's translatable integration closes the gap.Stack fit
Fits a conventional Laravel monolith or modular monolith with MySQL/Postgres. No fit with event-sourced or read-model-heavy architectures without wrapping it, because the trait writes synchronously to the pivot on model save. If we already run a search layer (Meilisearch, Typesense, Algolia, Elasticsearch), tags should be projected there for faceting and the DB pivot treated as system of record only — the package has no opinion on this.
Migration path
TagRepository / Tagger contract) so the trait is the only place vendor code appears.taggables semantically compatible with Spatie's taggables (taggable_type, taggable_id, tag_id). Where the schemas align, the exit is a package swap plus trait removal; where they diverge (translation tables, slug columns), it is a backfill script.Compatibility
Verify before committing: PHP constraint, illuminate/* constraint, whether migrations use legacy or anonymous class syntax, whether translation support requires spatie/laravel-translatable at a specific major, and whether the JSON/translation columns are supported on our target DB (MySQL 5.7+ or 8, Postgres jsonb). Also verify the pivot has no foreign keys to tags — polymorphic pivots usually don't, which has downstream consequences (see Failure modes).
Sequencing
Tagger contract, add integration tests covering orphan cleanup and concurrent tag creation.Maintenance
This is the dominant cost. Archiving transfers 100% of maintenance to us: framework upgrades, security patches in the dependency chain, bug fixes, and PHP version bumps. Realistically that is a small but permanent tax — a few days per year in steady state, plus a spike at every Laravel major. It also means the package appears in our fork register, needs a CI job running its test suite against our matrix, and needs an owner in the on-call/ownership map. Compare against a maintained dependency where that work is amortized across a community.
Support
No upstream support channel, no issue triage, no maintainer to escalate to. Internal L1/L2 support must own any tagging defect end to end. Documentation on the repo will drift from our usage; the authoritative reference becomes our own README and tests. Bus factor is effectively one — whoever runs the spike.
Scaling
The pivot pattern is fine well into the millions of rows provided indexes are correct: composite index on (taggable_type, taggable_id) for "tags of this model," and (tag_id, taggable_type) for "models with this tag." Tag clouds and facet counts are the scaling trap — COUNT(*) GROUP BY tag_id over a large pivot will not hold, so plan a denormalized taggables_count on tags maintained transactionally, or push counts into the search index. Translation support adds a join per read; cache the tag vocabulary (it is small, slowly changing reference data) rather than querying per request. The package itself has no caching layer, so this is our build.
Failure modes
taggables rows behind unless a model deleting hook cleans up, and the package may or may not provide it reliably. Silent data corruption that surfaces as inflated tag counts.slug (and a caught QueryException) prevents it. Confirm the published migration includes it; if not, add it.en but requested in de returns empty rather than falling back, depending on the translatable config. This produces blank UI labels in production, not in tests.sync-style arrays bypasses model events, so counters and search projections drift.Ramp-up
Low for engineers: the API is idiomatic Laravel and the concept is universally understood, so a mid-level developer is productive in under an hour. The ramp-up cost sits with maintainers, not users — understanding the forked code well enough to patch it during a framework upgrade. Budget a half-day of knowledge transfer and a written runbook at fork time.
TPM recommendation: default to spatie/laravel-tags; adopt Rinvex only if translated tag names are a hard launch requirement that Spatie cannot meet, and only with a named internal owner, a pinned fork, and the Tagger abstraction in place from the first commit.
How can I help you explore Laravel packages today?