django-treebeard: three ways to store a tree behind one Django API
Efficient tree implementations for Django
At a glance
- What is it?
- django-treebeard gives a Django project efficient tree structures, and the interesting part is that you can change the storage strategy without rewriting the code that uses it, since the adjacency list, materialized path and nested sets implementations share one API. The costs are a major API change in version 6 and a mismatch in the README's own count of implementations.
- Who is it for?
- Adopt django-treebeard if your Django project needs a hierarchy that will grow, if you want the option to change the storage strategy later, and if you are on Django 5.2 or newer with Python 3.10 or newer. Do not adopt it for a shallow tree that a foreign key handles, or if you need the experimental PostgreSQL ltree implementation to be production ready.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Three strategies, one interface, and a fourth experiment
The pitch of django-treebeard is a sentence: a library that implements efficient tree implementations for the Django Web Framework. The mechanism behind that is a shared API.
The README lists the implementations, and the list is worth reading carefully because of how it is worded. The features section says the library includes 3 different tree implementations with the same API, and then enumerates four: adjacency list, materialized path, nested sets, and PostgreSQL ltree, the last one marked experimental.
So the count in the prose and the count in the list disagree by one, and the fourth entry is the one that is not production ready. In practice the library gives you three complete strategies with a common interface, plus a fourth that is still being worked on.
The strategies differ in how the hierarchy is stored. An adjacency list keeps a parent pointer on each row. A materialized path stores the ancestry of each node as a sequence of path components on the node itself, so a subtree is a range query. Nested sets store a left and a right boundary value per node, so a subtree is a containment query. Each of those layouts has different costs for reads and writes, and the whole point of the library is that your application code does not have to care which one you picked.
The other claims in the features list are short. The tree operations are described as optimized and non-naive. The code base is described as testable and well tested, with code and branch test coverage above 96%. The project was written by Gustavo Picón and is licensed under the Apache License 2.0.
Models are declared by inheriting from an abstract class
The way you use the library is described in the features list under Easy: it uses Django Model Inheritance with abstract classes to define your own models.
That is the whole integration model. You do not install anything into your project, you do not register a custom field type, and there is no middleware. You define a model the way you define any other Django model, except that one of your base classes comes from treebeard and is marked abstract, and the tree methods come with it.
The practical effect is that the tree API is a set of methods on your model and its manager rather than a separate service. When you call get_children, get_descendants, get_ancestors or add_child, you are calling a method on the model instance or its manager, and the implementation behind the call depends on the strategy you inherited from.
This also explains why the README is comfortable claiming the library is easy to use. There is no wiring step, no configuration file and no migration of existing data to think about at install time. What there is instead is a modelling decision, and it is permanent in one direction: your model inherits a strategy, and the strategy is what the storage looks like in the database.
That last point is where the shared API earns its keep, and also where it can disappoint. Because the interface is the same, the application layer is portable between strategies. The database schema is not, since the columns that hold the tree differ, and there is no indication in the README that a conversion utility is provided.
Version 6 moved the API onto the model manager
The one upgrade in the README's history section is the reason to read the changelog before you pin a version.
Version 6 of Treebeard featured an API change that moved much of Treebeard's API from the model class to the model manager. In Django terms, the calls that used to be made on the model itself moved to the model's manager, which is the object returned by Model.objects.
For an application that calls these methods in a handful of places, that is a mechanical change. For a codebase that uses them widely, especially in templates or in expressions evaluated per row, it is a sweeping one, and it is the kind of change that turns a routine dependency bump into a project.
The project handled the transition by extending the life of the older line. The v5.x line receives security and bugfix releases until April 2030, explicitly to mitigate the upgrade burden, while v6.x receives security and bugfix support until April 2028 and v7.x is the current stable release.
That is a well managed deprecation, and it also tells you which line to be on. If you are starting a new project, v7.x is the current stable release. If you are running v5.x in production, you have until April 2030 for security and bugfix support, which is a long runway to schedule the migration. If you are on v6.x, your support window is the shortest of the three, and the README's wording suggests v7 is where the project is heading.
Four database back-ends and one experimental type
The system requirements section is short and specific. django-treebeard officially supports Django 5.2 and higher, Python 3.10 and higher, and the PostgreSQL, MySQL, MSSQL and SQLite database back-ends.
Four back-ends is a wide reach, and it follows from the design. The three complete strategies encode the tree in ordinary columns, so they work on any database Django supports. The fourth implementation, PostgreSQL ltree, is different in kind: it delegates the tree structure to a native database type rather than managing the path in application columns, which is why it is limited to one database and why it is flagged as experimental.
The difference in approach is worth being explicit about, because it is the reason to consider the experimental option rather than to avoid it. With the three built in strategies, the library owns the encoding and the queries, and the database sees ordinary columns and ordinary indexes. With ltree, the database understands the hierarchy itself, which moves work out of the application and into the engine, at the cost of a feature that is not finished and that ties you to one back-end.
The package metadata agrees with the README about the requirements. The pyproject file sets requires-python to >=3.10 and the only runtime dependency is django>=5.2, and the classifiers list Django 5.2, 6.0 and 6.1 alongside Python 3.10 through 3.14. The version is read dynamically from treebeard.__version__ rather than being hard coded in the manifest, so the package version always comes from the source of truth in the code.
What is in the repository beyond the package
The tree in the repository shows a project that treats its own infrastructure seriously, which is a reasonable signal for a library that other people depend on.
There is a docs/ directory, and the documentation badge in the README points at django-treebeard.readthedocs.io with the latest version, so the published documentation is the reference rather than the README, which is a short summary by design. There is a CHANGES.md, and the project URLs section in the manifest links to it as the changelog, so it is the file to read before an upgrade. There is a SECURITY.md, a CODE_OF_CONDUCT.md and an AUTHORS file.
There are two licence files, LICENSE and LICENSE-THIRD-PARTY, which is the arrangement a project uses when it ships code with licences of its own and dependencies under different terms. The manifest declares Apache-2.0 as the project licence. Whether the third party file covers anything you redistribute is a question for your own review, and the file itself is where the answer is.
For development, the repository carries a .pre-commit-config.yaml, a tox.ini, a pytest.ini, a .coveragerc and a .readthedocs.yaml, and the requirements file is explicitly for working on treebeard rather than for installing it. It lists ipython, ipdb, django_extensions and psycopg[binary] under Developing, and tox>=4.0 under Testing. The optional test extra in the manifest is the other half of that story, with pytest-django and pytest-pythonpath, and the manifest also pins the ruff configuration with a line length of 120 and the pylint error, pyupgrade, isort, pyflakes and pycodestyle rules selected.
Adding it to a project and choosing a strategy
The README does not include an install command, so there is nothing to copy into a terminal here. The distribution channel is the PyPI package django-treebeard, whose page is linked from the README badges, and the documentation site is the place to read how the model classes are meant to be used.
What the manifest does tell you is the shape of the dependency. The runtime requirement is a single package, django>=5.2, and there is no separate database driver requirement, because the driver belongs to your project and depends on the back-end you use. The package name is django-treebeard while the import package is treebeard, and the manifest restricts the packaged modules to that treebeard package alone.
So the first real use is a modelling decision rather than a command sequence. You pick the strategy that matches how the tree is read and written in your application, you declare your model on the corresponding abstract base, and you add the tree fields to the model, which means a migration in the ordinary Django way.
Which strategy suits which shape of problem is a question the documentation has to answer rather than the README, but the trade-off can be stated from the storage layouts alone. An adjacency list is the simplest to reason about and the most expensive to query for a whole subtree, because it walks parent pointers. A materialized path makes a subtree a range read and makes a move expensive, since the path has to be rewritten for the descendants. Nested sets make subtrees and ancestors cheap reads and moves expensive for the same reason.
The decision is worth making once and making deliberately, because the shared API will not make the storage decision for you later.
Editorial conclusion
Adopt django-treebeard if your Django project needs a hierarchy that will grow, if you want the option to change the storage strategy later, and if you are on Django 5.2 or newer with Python 3.10 or newer. Do not adopt it for a shallow tree that a foreign key handles, or if you need the experimental PostgreSQL ltree implementation to be production ready. Verify first which supported version line you are on, since version 6 moved much of the API from the model class to the model manager, read CHANGES.md before upgrading across that boundary, and confirm that the database you use is one of the four back-ends the project officially supports.
Frequently asked questions
Which tree implementations does django-treebeard provide?
The README's features list names adjacency list, materialized path, nested sets and PostgreSQL ltree, with the last one marked experimental, while the surrounding sentence says the library includes 3 different tree implementations with the same API. The three complete strategies share one API and the ltree implementation is the experimental addition.
What does django-treebeard require in terms of Django and Python?
The system requirements section states Django 5.2 and higher and Python 3.10 and higher, and the package manifest agrees with requires-python = ">=3.10" and a single runtime dependency of django>=5.2.
What changed in Treebeard version 6?
Version 6 featured an API change that moved much of Treebeard's API from the model class to the model manager. To mitigate the upgrade burden, the v5.x line receives security and bugfix releases until April 2030, v6.x until April 2028, and v7.x is the current stable release.
Which databases does django-treebeard support?
The README lists PostgreSQL, MySQL, MSSQL and SQLite as the officially supported database back-ends. The PostgreSQL ltree implementation is marked experimental, so it is tied to one back-end and is not finished.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/django-treebeard-django-treebeard)Was this useful?