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

Filament Nestedset Laravel Package

wsmallnews/filament-nestedset

Filament nestedset tree plugin built on kalnoy/nestedset, with multi-language and multi-tenancy support, unlimited nesting levels, tabbed switching, and a parent select field for elegant tree management.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Package: wsmallnews/filament-nestedset ^2.0 — MIT, 22 GitHub stars, 0 dependents, active releases (latest 2026-09-03), CI test + code-style workflows present.

Architecture fit

The package is a presentation-layer plugin, not a domain library. It supplies a NestedsetPage base class, a make:filament-nestedset-page generator, and a standalone Livewire tree component that render against any Eloquent model using Kalnoy\Nestedset\NodeTrait. That is the right architectural shape for a TPM to approve: it does not own your data model, does not impose a repository or service layer, and does not touch your query builder beyond a getEloquentQuery() hook.

Composition is layered and legible:

Layer Owner Coupling
Tree storage & move/insert algebra kalnoy/nestedset (mature, widely used) Low — you own the schema via $table->nestedSet()
Parent picker field codewithdennis/filament-select-tree Medium — transitive dependency, separate maintenance
Tree UI, pages, tabs, tenancy wiring this package Medium — you subclass NestedsetPage
UI shell, actions, forms, infolist Filament v4/v5 High — hard version coupling

The extension surface is idiomatic Filament (schema(), createSchema()/editSchema(), infolistSchema(), static page properties, getRecordLabel() returning HtmlString). A Laravel team can onboard without reading package internals. That materially lowers integration cost.

Two architectural caveats:

  1. Nested set is a write-expensive model. Every insert or drag-drop reparent rewrites _lft/_rgt across a contiguous range of rows. This is fine for navigation menus and category trees (hundreds of nodes, infrequent edits) and a poor fit for high-churn or high-concurrency hierarchies. This is a property of the chosen algorithm, not a defect in the plugin, but it is the single most important architectural constraint and it must be matched to the use case before adoption.
  2. Scoping is the load-bearing feature. Multi-tenancy and tabs are both implemented by delegating to kalnoy/nestedset's scoped-tree feature, driven by getScopeAttributes() on the model. Correctness of tenant isolation therefore depends on a convention split across two files (model + page) with no compile-time or runtime guarantee that they agree. That is a real correctness risk for a multi-tenant SaaS, and it is the thing I would insist on testing hardest.

Integration feasibility

Feasible, with a short path. Concretely required work:

  • composer require wsmallnews/filament-nestedset:^2.0
  • Publish config (sn-filament-nestedset-config), optionally views and translations
  • Add NodeTrait to the model; add $table->nestedSet() to the migration (new or existing table)
  • Generate and subclass the page; set $recordTitleAttribute, form schema, navigation metadata
  • For tenancy/tabs: add getScopeAttributes() to the model and the corresponding columns (team_id, type, etc.)

That is roughly a one-to-two-day integration for a competent Filament developer on a greenfield table. The cost multiplier is (a) existing data needing backfill and (b) tenancy semantics.

Notable friction points I would flag before committing:

  • Dual Filament v4/v5 support is a benefit for upgrade headroom but means the package maintains a compatibility matrix. Confirm your pinned Filament minor is in the tested set rather than assuming ^4 || ^5 is uniformly green.
  • autoload_assets => true globally injects CSS. Any project with a custom Filament theme must flip this off and import the stylesheet itself — an easy-to-miss step that produces a silently unstyled tree.
  • Transitive dependency on filament-select-tree adds a second small-maintainer package to your supply chain for what is functionally one form field. Acceptable, but it belongs in the dependency-risk register.
  • Livewire component surface (sn-filament-nestedset-leaf-click / node-click events, view/recordView overrides, getRecordUrl) is the right escape hatch when page-level abstraction is too coarse. It also means custom behavior can drift from the page component's behavior over time.

Technical risk

Risk Severity Likelihood Mitigation
Bus factor — effectively one maintainer, 22 stars, 0 dependents High Medium Vendor/fork under your org; MIT permits it. Budget ~1 dev-week/yr of maintenance headroom
Tenant scope misconfiguration leaks or cross-contaminates trees High Medium Feature tests asserting scope isolation on move, create, delete; code review gate on getScopeAttributes()
Tree corruption from writes outside NodeTrait (seeders, imports, raw SQL, admin tools) Medium High Enforce model-level writes only; run fixTree() in a scheduled integrity check until trust is established
Nested-set write amplification under concurrent drag-drop Medium Medium Accept for low-churn trees; add DB transaction + row locking on move; do not use for >5k nodes or multi-editor hot paths
Filament v5 breaking changes Medium Medium Pin minor versions; upgrade in a branch with the package's CI green first
Package abandonment mid-program Medium Low-Medium Fork-ready posture from day one: no edits inside vendor/, all customization via subclassing

The 23/100 composite score with 0 dependents is the honest signal here: this is unproven at scale, not defective. The code quality indicators that do exist (CI tests, code style workflow, changelog, releases, published config/views/translations, documented extension points, Laravel Boost guidelines) are all marks of a maintainer who intends the package to be used. That moves it from "avoid" to "adopt with guardrails" for the right use case.

Key questions

  1. What is the expected node count and edit frequency per tree? Above ~5k nodes or with more than a couple of concurrent editors, nested set is the wrong algorithm and we should stop here.
  2. Is this a single-tenant or multi-tenant deployment? If multi-tenant, getScopeAttributes() correctness becomes a security-relevant review item, not a config detail.
  3. Does the target table already exist with data? If so, what is the backfill and fixTree() plan, and is there a rollback?
  4. Which Filament major are we standardizing on, and does the package's tested matrix cover our exact minor?
  5. Do we have a custom Filament theme (affects autoload_assets)?
  6. Who owns the fork if upstream goes quiet — and do we have the Laravel/PHP capacity to maintain it?
  7. Are the tabs use case and the tenancy use case actually distinct datasets, or are we using tabs to model something a filter would handle better?

Integration Approach

Stack fit

Strong fit for a Filament v4/v5 admin panel on Laravel where the hierarchy is a content-organizing concern (navigation menus, category trees, org/department structures, CMS page trees) rather than a hot transactional workload. The abstraction level is right: you subclass a page, declare a form schema, and get drag-drop, reparenting, level limits, empty states, and per-row infolist for free. That is a genuine TPM win — the alternative is one to two sprints of bespoke Livewire tree work plus the ongoing cost of owning drag-drop UX.

Poor fit if any of the following hold: hierarchy is edited at high concurrency; node count is in the tens of thousands; the tree must be edited through an API rather than the panel; or the team is not on Filament at all.

Stack prerequisites to confirm in a spike: PHP and Laravel constraints from composer.json, Filament minor within the tested matrix, and kalnoy/nestedset compatible with the target Laravel version.

Migration path

Greenfield table — the cheap path. Add $table->nestedSet() in the create migration, NodeTrait on the model, seed through the model (never raw inserts), done.

Existing table with parent_id only — the common real-world case:

  1. Add nullable _lft/_rgt columns via $table->nestedSet() in a separate migration.
  2. Backfill in a queued/one-off command using NodeTrait::fixTree(), chunked and logged.
  3. Verify with an integrity assertion (every node's _lft < _rgt, no overlapping ranges, parent_id consistent with range containment).
  4. Only then remove any legacy parent_id-only code paths, ordering assumptions, or recursive loaders.

Tenant-scoped migration — the highest-risk path:

  1. Backfill team_id on existing rows before enabling scoping; unscoped rows in a scoped tree are a correctness bug, not a cosmetic one.
  2. Run fixTree() per scope value, not globally — scoped trees are independent range spaces.
  3. Ship behind a feature flag; validate one tenant before rolling to all.

Rollback posture: keep the migration reversible and keep a pre-migration snapshot of the table. Tree backfills are recoverable only from backup in practice.

Compatibility

  • ^2.0 targets Filament v4/v5; Filament v3 users must install the v1 branch. Confirm which branch matches our panel before evaluating further — the v1 branch is a different codebase and should be assessed separately.
  • Pin to an exact minor (^2.x.y with a lockfile) and treat Filament major upgrades as a joint upgrade with this package.
  • The codewithdennis/filament-select-tree transitive dependency must be reviewed at the same time as the parent package; its Filament constraints are on the critical path.
  • Locale coverage: translations are publishable, but verify target locales are actually present rather than assuming "multi-language support" means our locales.
  • Laravel Boost integration is optional tooling, not a runtime dependency. It is a developer-ergonomics nicety for AI-assisted work; it should not appear in the architecture decision record.

Sequencing

A four-phase sequence with a decision gate after phase 2:

Phase Scope Exit criterion
0 — Spike (2–3 days) Throwaway branch; one model, one page, seeded ~500 nodes; exercise drag-drop, reparent, level limit, delete guards Documented answer to node-count/concurrency questions; confirms Filament minor compatibility
1 — Single-scope pilot One real tree, non-tenant, e.g. admin navigation or a category set. No tabs, no tenancy Ships to internal users; tree survives a week of real editing without corruption
2 — Scoping Enable tabs OR tenancy (not both at once). Feature tests for scope isolation Isolation tests green under create/move/delete; integrity check clean
3 — Breadth Remaining trees; second scoping dimension; Livewire component reuse if needed Fork-and-patch runbook documented; owner named

Decision gate after phase 0/2: if the spike reveals node counts or concurrency in the "wrong algorithm" band, stop and evaluate a closure-table or materialized-path implementation instead. Better to spend three days finding that out than a quarter.

Deliberately do not do phases 1 and 2 simultaneously. Tabs and tenancy both route through getScopeAttributes(), and debugging a scoped-tree bug when two scope dimensions are live at once is materially harder than doing them in series.


Operational Impact

Maintenance

The real maintenance question is not "does it work" but "who fixes it when it breaks at 2 a.m." With one effective maintainer and zero dependents, the honest answer is: we do. That is not disqualifying under MIT — but it has to be planned for, not discovered.

Recommended posture:

  • Fork-ready from day one. No edits inside vendor/. All customization via subclassing NestedsetPage, overriding getRecordLabel(), getEloquentQuery(), nestedScoped(), schema(). This keeps the fork-and-patch option cheap.
  • Name an owner. One engineer accountable for upstream tracking, not a team amorphous responsibility.
  • Upstream tracking at low cadence. Watch releases; review the changelog on each minor. The package releases frequently enough that a quarterly review is the right rhythm.
  • Maintenance budget: ~2–5 dev-days per year in steady state, spiking to a week or two on a Filament major upgrade. If that number is unacceptable, the build-versus-buy math tilts toward building a minimal tree yourself.
  • Do not fork preemptively. A fork diverges on day one and costs more than it saves until upstream actually stalls.

Support

Community-only: GitHub issues, no vendor SLA, no commercial support tier, single-maintainer response cadence. Documentation is a thorough README plus a CHANGELOG — good for feature discovery, thin on troubleshooting, edge cases, and failure recovery. There is no separate docs site.

Practical consequence: the team's internal notes become the real documentation. Budget for a short internal runbook covering: how to add a tree, how scoping is wired in our codebase, how to run an integrity check, and how to recover a corrupted tree. That runbook is the mitigation for the support gap, and it is cheap to write during the pilot while the knowledge is fresh.

Scaling

Scaling characteristics are inherited from kalnoy/nestedset, and they are asymmetric:

  • Reads scale well. A subtree is one indexed range query (_lft BETWEEN x AND y), independent of depth. Render cost for the tree UI is the practical limit, not the query.
  • Writes do not scale. A single reparent rewrites every row whose _lft/_rgt falls in the affected range. Moving a root-level node in a 2,000-node tree rewrites ~2,000 rows. That is a long transaction holding locks.
  • Concurrent editing is the sharpest edge. Two admins dragging nodes in the same tree at the same time can interleave structural writes. Nested set has no built-in optimistic concurrency. Mitigations: wrap moves in a transaction with row locking, and/or accept that this is an internal admin tool where simultaneous structural edits are rare and a "refresh, someone else changed the tree" experience is tolerable.
  • Mitigation: enforce a node ceiling. Set an explicit documented limit (I would suggest 2,000–5,000 nodes per tree) and validate against it in the spike. Beyond that, revisit the algorithm.
  • Vertical scaling is the answer, not horizontal. Read replicas do not help structural writes; the tree's writes must go to the primary.

Failure modes

Failure Symptom Detection Recovery
Tree corruption from out-of-band writes Nodes missing from UI, wrong nesting, duplicate positions Scheduled integrity assertion (_lft < _rgt, no overlap, parent containment) fixTree() per scope; restore from backup if severe
Cross-tenant scope leakage Tenant A sees or moves Tenant B's nodes Feature test on scope isolation; manual QA with two tenants Immediate hotfix; audit getScopeAttributes() vs page config
Stale UI after concurrent edit Drag-drop appears to succeed but reverts on reload User reports Locking on move; explicit refresh affordance; acceptable for internal tooling
Delete guard confusion (allow_delete_parent / allow_delete_root) User cannot delete what they expect to delete, or deletes a subtree unintentionally Config review at integration Set both explicitly and document the intended semantics for each tree
Asset loading conflict with custom theme Unstyled or double-styled tree Visual QA Set autoload_assets => false, import CSS in theme
Upstream incompatibility after Filament upgrade Page class breaks, tree fails to render CI + staging Pin versions; upgrade jointly; fork if needed
Migration backfill failure on large existing table Timeout, partial tree Backfill command logging + row-count assertions Idempotent re-runnable command; restore snapshot

The two failures that actually hurt are silent tree corruption and scope leakage — both invisible until a user notices. Both are cheap to defend against with a scheduled integrity check and a scope-isolation test suite. Those two artifacts are the highest-value operational investment in this whole assessment and should be non-negotiable acceptance criteria for the pilot.

Ramp-up

Low, and that is one of the package's genuine strengths.

  • Filament-fluent developer: ~half a day to a working page using the README; one to two days to a production-quality tree with correct schema, navigation, and empty states.
  • The real learning curve is nested set semantics, not the plugin. Understanding scoping, fixTree(), and why writes are expensive takes longer than learning the API. That knowledge should be concentrated in one or two people, not spread thin.
  • Tenancy/tabs add meaningful complexity. A developer who has only built single-scope trees will misconfigure getScopeAttributes(). Pair on the first scoped tree.
  • Team-wide: roughly one hour of onboarding for anyone who only needs to use the tree in the admin panel — the UI matches Filament conventions and needs no explanation.

Overall TPM recommendation: adopt for internal Filament admin trees where node counts are modest and edit concurrency is low, conditional on (1) a successful 2–3 day spike confirming the algorithm fits the node-count/concurrency profile, (2) scope-isolation tests as a merge gate if multi-tenant, (3) a named maintainer with a documented fork-ready posture, and (4) a scheduled tree-integrity check. Do not adopt for high-concurrency hierarchies, very large trees, or any context where an unsupported single-maintainer dependency is unacceptable to the organization.

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.
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
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