# lazychaser/laravel-nestedset: Tree Structures in Laravel with the Nested Set Model

> kalnoy/nestedset is a Laravel package that implements the Nested Set Model for storing hierarchical data in relational databases. It targets Laravel developers who need efficient read-heavy tree queries, such as multi-depth menus or product categories, and accepts that write operations are more expensive than in adjacency-list approaches.

**lazychaser/laravel-nestedset** — Effective tree structures in Laravel 4-8

- Repository: https://github.com/lazychaser/laravel-nestedset
- Stars: 3,804 · Forks: 478
- Language: PHP
- License: not declared
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/lazychaser-laravel-nestedset

## The Problem: Hierarchical Data in Relational Tables

Storing a tree in a relational table has two common approaches. An adjacency list stores only a parent_id on each row. Queries are simple to write but retrieving an entire subtree requires recursive joins or multiple round trips, which is expensive at depth.

The Nested Set Model takes a different approach. Each node stores two numbers, a left value and a right value, assigned by a tree traversal that visits each node twice. Hierarchy membership can then be tested by comparing these numbers: if a node's left and right values fall within those of another node, it is a descendant. The README quotes the Wikipedia description directly: updating requires renumbering and is expensive, but querying is inexpensive.

kalnoy/nestedset encodes this model as a Laravel Eloquent package. It adds the left, right, depth, and parent_id columns to a table, exposes relationships for ancestors, descendants, and children, and provides methods for inserting, moving, and querying nodes. According to the README, it shows good performance when the tree is updated rarely and is ideally suited for multi-depth menus or shop categories.

## Laravel Version Support and Installation

The package has tracked Laravel major versions closely. The README lists the mapping: Laravel 13 is supported from v7.0.0 onward, Laravel 12 from v6.0.7, Laravel 11 from v6.0.4, Laravel 10 from v6.0.2, and Laravel 9 from v6.0.1. Earlier Laravel versions back to Laravel 4 were supported by older package versions. The repository is hosted on Packagist under the name kalnoy/nestedset.

To add the package to a Laravel project:

```bash
composer require kalnoy/nestedset
```

After installation, the migration for the target model needs to add the nested set columns. The package handles the column definitions through its own helpers. A node model then uses the NodeTrait trait to gain the full set of tree query and manipulation methods. The README describes the model as `Category` in its examples, but the trait applies to any Eloquent model.

## Inserting and Moving Nodes

The README notes that moving and inserting nodes involves several database queries, and recommends wrapping structural changes in transactions. As of version 4.2.0, transactions are not started automatically, so application code must handle them explicitly.

Creating a root node uses the standard Eloquent create path:

```php
Category::create($attributes); // Saved as root
```

To place a node as a child of an existing node, the package offers several equivalent methods. The most direct uses the parent node directly:

```php
$node->appendToNode($parent)->save();
```

Alternatively, calling `$parent->appendNode($node)` or creating through the children relationship both produce the same result. Prepending to a parent uses `prependToNode` or `prependNode`. Inserting at a specific position relative to a sibling uses `afterNode` or `beforeNode` before calling `save`.

After a save, the README notes that a successful save does not guarantee the node changed position if a structural manipulation was attempted. Applications that depend on knowing whether the node moved should call `hasMoved` after save:

```php
if ($node->save()) {
    $moved = $node->hasMoved();
}
```

## Rebuilding Trees and Bulk Operations

For mass restructuring, the package provides a static rebuildTree method that accepts an array representation of the tree:

```php
Category::rebuildTree($data, $delete);
```

The $data array uses nested 'children' keys to describe hierarchy. Nodes with a matching primary key are updated in place. Nodes without a key are created. The $delete parameter controls whether existing nodes absent from the input are deleted. As of version 4.2.8, a complementary method rebuildSubtree limits the rebuild to the descendants of a given root node.

This bulk method is useful when a front-end drag-and-drop interface produces a new complete tree structure that needs to replace the database state in a single operation. The README warns that the method still triggers the underlying renumbering logic, so a large restructure on a large table will be slow.

## Querying Ancestors, Descendants, and Subtrees

The package exposes four eager-loadable relationships on every node: parent, children, ancestors, and descendants. Ancestors form the chain of parents from the node up to the root, which is useful for rendering breadcrumbs. Descendants include all nodes in the entire subtree below the node.

These relationships work with standard Eloquent eager loading:

```php
$node->ancestors;
$node->descendants;
```

Because the Nested Set Model stores left and right values, the query for all descendants is a single range comparison on those columns, not a recursive join. This is the key performance advantage over adjacency-list trees: fetching a subtree at any depth costs one query regardless of tree depth.

The package also supports scoping, which partitions tree operations across multiple independent trees in the same table. This is useful when the same model stores several unrelated hierarchies, such as category trees for multiple stores.

## Write Performance and the Cost of Tree Modifications

The Nested Set Model's read advantage comes at a direct write cost. Every structural change, whether inserting a node, moving it, or deleting it, requires updating the left and right values of every affected node. On a large table with thousands of rows, a single move operation can update hundreds of rows.

The README states this explicitly: updating requires renumbering and is expensive. It recommends the Nested Set Model only for trees updated rarely. This is a real constraint for applications where users can reorganize categories or reorder navigation items freely. A table with heavy concurrent writes will contend heavily on the column values during renumbering.

The package provides a consistency check feature that can detect and fix tables where the left and right values have become inconsistent, for example after a failed transaction or a direct database edit that bypassed the package. The README lists this under the heading "Checking consistency."

## Maintenance Status, License, and an Alternative

The last push to the lazychaser/laravel-nestedset repository was on 2026-04-11. The repository is not archived. The most recent release listed is v6.0.6, published on 2025-05-26. The package license is not stated in the repository metadata, though the README does not include a license section.

For projects that cannot accept the write overhead of nested sets, staudenmeir/laravel-adjacency-list is the main alternative. It stores parent IDs rather than left and right traversal values. Write operations are cheap because moving a node requires updating only the parent_id. The trade-off is that ancestor and descendant queries require recursive CTEs, which are not supported by all databases and may perform differently at scale compared to the range queries nested sets use.

## Conclusion

kalnoy/nestedset suits Laravel projects where tree data is read far more than it is written, such as a product category hierarchy or a navigation menu that changes infrequently. It is the wrong choice for trees that update constantly, because every structural change triggers a renumbering pass across the table. Before adopting, verify that the v7 branch supports your Laravel version, since the README maps each major Laravel release to a specific package version. Projects that cannot accept the write overhead should look at staudenmeir/laravel-adjacency-list, which stores parent IDs rather than left and right values.

## FAQ

### What columns does kalnoy/nestedset add to my database table?

The package adds left-value, right-value, depth, and parent_id columns to the model's table. These four columns store the nested set structure and are managed automatically by the package's trait methods.

### Does lazychaser/laravel-nestedset support Laravel 13?

Yes. The README states that Laravel 13 is supported since v7.0.0 of the package. Earlier Laravel versions are supported by correspondingly earlier package versions as documented in the README's compatibility table.

### Can laravel-nestedset handle multiple independent trees in the same table?

Yes, through scoping. The package supports partitioning tree operations so that multiple independent hierarchies can coexist in a single database table without interfering with each other.

## Sources

- [Issues](https://github.com/lazychaser/laravel-nestedset/issues)
- [lazychaser/laravel-nestedset on GitHub](https://github.com/lazychaser/laravel-nestedset)
- [README](https://github.com/lazychaser/laravel-nestedset/blob/v7/README.md)
- [Releases](https://github.com/lazychaser/laravel-nestedset/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/lazychaser-laravel-nestedset
