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

Bonsai Laravel Package

baril/bonsai

Closure Table pattern implementation for Laravel Eloquent that lets you store and query tree-like structures in a relational database. Provides fast ancestor and descendant lookups across all supported DBMSs, migration artisan commands, and an alternative to nested sets.

View on GitHub
Deep Wiki
Context7

Product Decisions This Supports

  • Build vs. buy for hierarchy features. Any roadmap item that reads "category tree," "nested folders," "org chart," "threaded comments," "menu builder," or "multi-level taxonomy" is the same underlying problem: storing and querying a tree in a relational database. Bonsai is a ready-made answer, so the decision shifts from "how many sprints to build tree logic" to "do we accept this dependency."
  • Feature scoping for ancestor/descendant queries. The package ships ancestorsOf(), descendantsOf(), withDepth(), withHeight(), maxDepth(), getDistanceTo(), and findCommonAncestorWith() as first-class scopes and methods. That directly enables features PMs usually defer: breadcrumbs, "browse this subtree" filters, subtree-scoped permissions or pricing, depth-limited navigation, and "related" recommendations based on shared ancestry — without a data-science or platform-level effort.
  • Cheap, low-risk experimentation. Adoption cost is a trait on the model plus one generated migration (bonsai:grow). A PM can greenlight a hierarchy-based feature as a spike rather than a committed platform investment, and validate with users before funding a bespoke tree service.
  • Roadmap flexibility on depth. Because ancestors/descendants are indexed join-table lookups rather than recursive queries, arbitrary-depth features are viable on day one. PMs don't have to promise "up to 3 levels for v1" — a common and expensive compromise.
  • Safer data-correction and support workflows. bonsai:fix truncates and rebuilds closures from the canonical parent_id column, and bonsai:show prints the tree with a chosen label and depth. That means a corrupted tree is a repair command, not a data-migration incident — a meaningful reduction in on-call and support burden that PMs should weigh in the risk column.
  • Operational decisions around deletion semantics. Explicit delete vs. deleteTree, hard delete vs. the package's SoftDeletes trait with restoreTree() / forceDeleteTree(), plus a TreeException when a parent disappears mid-restore. These are product policies ("what happens to a deleted category's children?") that the package forces you to answer deliberately rather than discover in production.
  • Ordering as a separate decision. If each level must be user-ordered (drag-and-drop menus, merchandised categories), the sibling baril/orderly package is a clean add-on. PM can decide "explicit ordering" as its own line item rather than folding it into the hierarchy epic.
  • Database and platform decisions. Version 3.3+ supports MySQL, PostgreSQL, SQLite, and SQL Server, and 3.5+ supports Laravel 13. This removes the "we can't use it because we're on Postgres" objection and keeps the choice independent of a planned DB migration.

When to Consider This Package

Adopt when most of these hold:

  • The hierarchy is genuinely deep or unbounded (categories, org units, folders, comment threads, location trees) and the product needs "all descendants," "all ancestors," or depth-based filtering as a routine query.
  • The tree is read-heavy but not write-frozen. Closure tables are excellent for arbitrary-depth reads and tolerate moderate structural churn (re-parenting, grafting). They are a poor fit for constant bulk re-parenting.
  • You are on Laravel 9–13 with Eloquent and want the hierarchy to look like ordinary relationships (parent, children, siblings, ancestors, descendants) so feature teams don't need special tree knowledge.
  • You need eager loading of whole subtrees in one query — with('descendants') recursively hydrates children with no additional queries, which matters for export, sitemap, or nested-JSON API endpoints.
  • Structural integrity matters. The package throws TreeException on cycles and prevents deleting a node with children unless you opt in via deleteTree(). That is product-grade guardrail behavior, not just a query helper.
  • Soft delete and ordered trees are on the roadmap. Both are supported, so you avoid a rewrite when those requirements arrive.

Look elsewhere when:

  • You need a graph, not a tree — a node with multiple parents (tagging, DAG-based dependency or BOM structures). Closure tables assume a single parent; this package will not model that.
  • Write throughput on the tree is high. Every insert or move writes O(depth) closure rows. Bulk imports, high-volume user-generated hierarchies, or frequent rebalancing will make the join table the bottleneck.
  • You want a large ecosystem and commercial support. At ~36 stars and zero dependents, this is a single-maintainer package. If procurement or security review requires a supported dependency, kalnoy/nestedset is the incumbent alternative with far greater adoption — at the cost of a harder-to-mutate nested-set encoding.
  • You need hierarchy support outside Laravel/PHP. Nothing here transfers.
  • Storage is tightly constrained. A closure table stores every ancestor-descendant pair, including self-references; for deep trees that is materially more rows than the source table.
  • You want the pattern without a dependency. Closure tables are a well-documented pattern; a small team could implement the subset it needs. Given a single-maintainer bus factor, "implement the 20% we use" is a legitimate competing option and should be priced honestly against the ~a day of integration this package costs.

How to Pitch It (Stakeholders)

For executives: This is a small, focused open-source library that gives us tree and hierarchy capability — categories, folders, org structures, nested navigation — without building it ourselves. Integration is roughly a trait on a model and one generated migration, so a hierarchy feature can be scoped as a normal backlog item rather than a platform program. The material risk is supportability: it is maintained by one person with a small user base. We mitigate that because the package's own design treats the closure table as derived data — the parent_id column remains the source of truth and a single artisan command rebuilds the tree index from scratch. Worst case, we fork or replace the indexing layer without a data migration. Recommendation: adopt behind a thin internal abstraction, ship one hierarchy feature on it, and revisit the dependency at the next architecture review. If the requirement is a multi-parent graph rather than a tree, this is the wrong tool and we should say so now.

For engineering: Eloquent-native closure table implementation. BelongsToTree trait gives you parent/children/siblings/ancestors/descendants, plus scopes (onlyRoots, onlyLeaves, descendantsOf, withDepth), predicates (isAncestorOf, isDescendantOf, getDistanceTo), and mutations (graft, graftOnto, cut). bonsai:grow generates the closure migration, bonsai:fix rebuilds it, bonsai:show inspects it. Cycles and orphan-causing deletes throw TreeException; deleteTree() handles cascades. Soft deletes and explicit sibling ordering (baril/orderly) are supported. Eager-loading descendants recursively hydrates children in one query. Trade-off to own: O(depth) write amplification per structural change, and a single-maintainer dependency — pin the version, keep the tree behind a repository/service boundary, and rely on bonsai:fix as the recovery path.

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.
steadrun/laravel-monitor
labyrinthe/connect-laravel
elmogy/layan
drewdan/sentinel-client
dskripchenko/laravel-llm
fatryst/nuonuo
stevenay/myanfont
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin