staudenmeir/laravel-adjacency-list
Laravel Eloquent extension that adds recursive relationships for tree and graph structures using common table expressions (CTEs). Traverse categories, page hierarchies, nested comments, and more across MySQL, PostgreSQL, SQLite, SQL Server, and MariaDB.
Architecture fit — This is a Laravel/Eloquent extension, not a standalone hierarchy service. It fits applications already using Eloquent with adjacency-list data: parent_id for trees, or pivot tables for graphs. It provides CTE-backed recursive relationships (ancestors, descendants, tree, bloodline, etc.), filters, depth/path columns, and nested-result conversion. A TPM can leverage it to avoid custom recursive PHP and repeated N+1 queries for common hierarchy reads: category trees, comment threads, org charts, menu structures, and permission graphs. It does not own tree integrity, move/copy semantics, authorization, or UI behavior; those remain product/application responsibilities. It is a poor fit for non-Laravel services or write-heavy hierarchy operations without additional design.
Integration feasibility — Low-to-moderate. Install via Composer, add HasRecursiveRelationships to models, and override parent/local keys where needed. The README documents customization for depth/path names, cycle detection, query constraints, custom paths, and descendant relationships. Laravel compatibility is explicit from 5.5 through 13, with package-version mapping. The main prerequisites are a CTE-capable database and clean parent-child data. Supported engines include MySQL 8.0+, MariaDB 10.2+, PostgreSQL 9.4+, SQLite 3.8.3+, SQL Server 2008+, and SingleStore 8.1+ for trees only. The package is niche but focused; zero listed dependents means less external validation, so internal testing matters more.
Technical risk — Moderate. Primary risks are CTE query performance on deep or wide trees, database-specific recursion behavior, cycle/infinite recursion, missing tenant or authorization scopes, and accidental mass updates/deletes through descendant relationships. Cycle detection must be enabled for mutable trees. whereDepth() still builds the full subtree internally unless paired with withMaxDepth(). Depth/path column names can collide with existing schema. Graph traversal is more complex and riskier than single-parent trees. SQLite is useful for tests but not representative of production scale. The package generates raw recursive SQL through Eloquent, so DBAs and backend reviewers should inspect query plans for hot paths.
Key questions — Which entities need hierarchy, and how deep/wide are they? Is the requirement a tree or a multi-parent graph? What database engine/version runs in each environment? What are the read/write ratios and latency SLOs? How will tenant, authorization, and soft-delete scopes be enforced inside recursive queries? Are cycles, orphaned nodes, or duplicate paths possible? Do we need ordered traversal, path/slug output, or nested JSON for APIs? What maximum depth is acceptable, and can hot trees be cached or materialized? What Laravel/PHP versions must be supported? Who owns upgrades, production support, and rollback?
Stack fit — Strong fit for a Laravel monolith or modular monolith using Eloquent and a CTE-capable database. It can be adopted incrementally, one model at a time. It is most valuable for read/traversal use cases and API read models. It is not a fit for teams needing hierarchy traversal outside Laravel, or teams unwilling to maintain CTE-backed SQL inside the ORM layer.
Migration path — Start with a model that already has parent_id and a bounded tree, such as categories. Add a nullable indexed parent_id if absent, backfill it, add the trait, and replace ad-hoc recursive PHP loops or N+1 queries with descendants(), ancestors(), tree(), and related scopes. Add tests for depth, ordering, filters, and tenant scoping. For graphs, prove a many-to-many pilot with a pivot table before broader adoption. Avoid descendant mass-update/delete features until authorization and cascade rules are tested.
Compatibility — Pin the package version to the application’s Laravel version using the README compatibility table. Validate PHP and database versions in CI. Test against production-like data, not only SQLite. Confirm recursive CTE settings and limits for each engine. Keep a fallback path using query builder or application-level recursion for unsupported engines or emergency rollback.
Sequencing — 1) Inventory hierarchical entities and current recursive queries. 2) Select a low-risk pilot with bounded depth. 3) Fix schema, indexes, and data integrity. 4) Install the package and configure the trait in the pilot model. 5) Replace existing queries and add automated tests across supported databases. 6) Add cycle detection, max-depth limits, and tenant/authorization scopes. 7) Benchmark with realistic volumes. 8) Roll out to the next model and document conventions. 9) Evaluate caching or materialized paths for hot trees. 10) Review after one release cycle.
Maintenance — Low code footprint but still an open-source dependency. MIT licensing is permissive. Active releases, code coverage, and PHPStan level 9 are positive signals. Maintainer concentration, niche adoption, and the supplied zero-dependent count are watch items. Pin versions, review changelogs on Laravel upgrades, verify release metadata before adoption, and keep a fork/escape plan. Database engine upgrades also require retesting recursive query behavior.
Support — Support is community-based through GitHub issues, not a vendor SLA. A TPM should name an internal owner, document model conventions, and create a runbook for slow recursive queries, cycle handling, failed deployments, and rollback. Escalation should be to internal engineering, not package maintainers.
Scaling — Scaling depends on indexes, tree depth/width, query constraints, and database capacity. Use withMaxDepth(), narrow initial/recursive constraints, and avoid loading entire large trees for request-path features. Cache or materialize frequently read trees. For write-heavy hierarchies, queue cascading operations and monitor. Graph traversal can multiply result sizes quickly; cap depth and require review before exposing it broadly.
Failure modes — Infinite recursion from cycles; database CTE recursion limits or timeouts; slow queries from missing indexes; cross-tenant data leakage if scopes are not applied; unexpected mass updates/deletes; depth/path column collisions; soft-delete or orphan handling gaps; unsupported database or package/Laravel mismatch; Composer upgrade breakage. Add monitoring for slow queries and recursion errors, and test failure scenarios before production rollout.
Ramp-up — Laravel developers should ramp quickly from README examples. Estimate 1–2 days for a simple tree pilot and 1–2 weeks for graph traversal, multi-tenant scoping, and performance hardening. A TPM should fund a short spike, code review, and internal documentation. Use the pilot to produce reusable patterns before expanding to additional models.
How can I help you explore Laravel packages today?