# How to Add Nodes to a treelib Tree: A Complete Guide

> Learn how to add nodes to a treelib tree using create_node or add_node. This guide simplifies node insertion for your Python tree structures.

- Repository: [Xiaming Chen/treelib](https://github.com/caesar0301/treelib)
- Tags: how-to-guide
- Published: 2026-02-26

---

**Use `Tree.create_node()` to build and insert a node in one step, or `Tree.add_node()` to attach an existing `Node` object to your tree.**

The `treelib` library (caesar0301/treelib) represents hierarchical data as a collection of `Node` objects managed by a `Tree` instance. Whether you are building an organizational chart, a file system, or an abstract syntax tree, understanding the two primary methods for adding nodes—`create_node()` and `add_node()`—ensures you can construct trees efficiently while maintaining internal consistency.

## The Two Methods for Adding Nodes

`treelib` exposes two high-level APIs for node insertion in [`treelib/tree.py`](https://github.com/caesar0301/treelib/blob/main/treelib/tree.py). Both perform identical internal bookkeeping, including pointer updates and validation, but differ in how the `Node` object is instantiated.

### Tree.create_node(): Create and Add in One Step

The `create_node()` method (defined at line 825 in [`treelib/tree.py`](https://github.com/caesar0301/treelib/blob/main/treelib/tree.py)) constructs a fresh `Node` instance using the tree’s configured `node_class` and immediately attaches it to the hierarchy.

```python
from treelib import Tree

tree = Tree()

# Create root node (parent=None, tree must be empty)

tree.create_node(tag="Company", identifier="company")

# Add children by specifying parent identifier

tree.create_node(tag="Engineering", identifier="eng", parent="company")
tree.create_node(tag="Sales", identifier="sales", parent="company")

```

When `parent` is `None`, the method validates that the tree is empty before establishing the root. If a parent is provided, `treelib` verifies that the parent identifier exists in the tree, raising `NodeIDAbsentError` from [`treelib/exceptions.py`](https://github.com/caesar0301/treelib/blob/main/treelib/exceptions.py) if not found.

### Tree.add_node(): Insert Existing Node Objects

The `add_node()` method (defined at line 844 in [`treelib/tree.py`](https://github.com/caesar0301/treelib/blob/main/treelib/tree.py)) accepts an already-constructed `Node` object. This is essential when using custom `Node` subclasses or when nodes are built by external factories.

```python
from treelib import Tree, Node

tree = Tree()

# Construct nodes manually

root = Node(tag="Root", identifier="root")
child = Node(tag="Child", identifier="child")

# Insert into tree

tree.add_node(root)                    # Becomes root

tree.add_node(child, parent="root")    # Child of root

```

Both methods ultimately delegate to the same internal logic that updates forward and backward pointers, ensuring tree integrity.

## Internal Mechanics of Node Addition

When you call either `create_node()` or `add_node()`, `treelib` performs several validation and bookkeeping steps in [`treelib/tree.py`](https://github.com/caesar0301/treelib/blob/main/treelib/tree.py) to maintain the tree structure.

### Pointer Management and Tree Integrity

The library maintains bidirectional relationships between nodes:

1. **Forward pointer update**: The parent’s successor list is updated via `__update_fpointer` (line 1037 in [`treelib/tree.py`](https://github.com/caesar0301/treelib/blob/main/treelib/tree.py)), adding the new child identifier to the parent’s children list.
2. **Backward pointer update**: The child’s predecessor is set via `__update_bpointer` (line 1040 in [`treelib/tree.py`](https://github.com/caesar0301/treelib/blob/main/treelib/tree.py)), establishing the link back to the parent.
3. **Tree ID registration**: The node records the tree’s unique identifier via `set_initial_tree_id` (line 1042 in [`treelib/tree.py`](https://github.com/caesar0301/treelib/blob/main/treelib/tree.py)), enabling multi-tree support and preventing cross-tree contamination.

### Validation and Error Handling

The [`treelib/exceptions.py`](https://github.com/caesar0301/treelib/blob/main/treelib/exceptions.py) module defines specific errors raised during node addition:

- **`DuplicatedNodeIdError`**: Raised by `add_node()` (line 998 in [`treelib/tree.py`](https://github.com/caesar0301/treelib/blob/main/treelib/tree.py)) if the identifier already exists in the tree.
- **`MultipleRootError`**: Raised when attempting to add a second root node (parent is `None` but tree is not empty).
- **`NodeIDAbsentError`**: Raised when the specified parent identifier does not exist in the tree.

These validations ensure that tree operations remain safe and deterministic.

## Practical Code Examples

### Building a Hierarchy with create_node()

This example demonstrates creating a complete organizational chart using the convenience method:

```python
from treelib import Tree

tree = Tree()
tree.create_node("CEO", "ceo")                           # Root

tree.create_node("CTO", "cto", parent="ceo")             # Level 1

tree.create_node("CFO", "cfo", parent="ceo")             # Level 1

tree.create_node("Dev Lead", "dev_lead", parent="cto")   # Level 2

tree.create_node("Developer", "dev1", parent="dev_lead") # Level 3

tree.show()

```

Output:

```

CEO
├── CTO
│   └── Dev Lead
│       └── Developer
└── CFO

```

### Using Custom Node Subclasses

For advanced use cases, subclass `Node` and pass `node_class` to the `Tree` constructor:

```python
from treelib import Tree, Node

class FileNode(Node):
    def __init__(self, tag, identifier=None, data=None, file_size=0):
        super().__init__(tag, identifier, data)
        self.file_size = file_size

tree = Tree(node_class=FileNode)

# Create nodes manually then add them

root = FileNode("Root", "root", file_size=0)
file1 = FileNode("document.txt", "doc1", file_size=1024)

tree.add_node(root)
tree.add_node(file1, parent="root")

print(f"File size: {tree.get_node('doc1').file_size} bytes")

```

This approach leverages `add_node()` to insert pre-constructed custom objects while maintaining the tree structure defined in [`treelib/tree.py`](https://github.com/caesar0301/treelib/blob/main/treelib/tree.py).

## Summary

- **Two entry points**: Use `Tree.create_node()` for one-step creation and insertion, or `Tree.add_node()` to attach existing `Node` objects.
- **Internal consistency**: Both methods update bidirectional pointers (`__update_fpointer` and `__update_bpointer` in [`treelib/tree.py`](https://github.com/caesar0301/treelib/blob/main/treelib/tree.py)) and register the tree ID to prevent cross-tree contamination.
- **Robust validation**: The library raises specific exceptions from [`treelib/exceptions.py`](https://github.com/caesar0301/treelib/blob/main/treelib/exceptions.py) (`DuplicatedNodeIdError`, `MultipleRootError`, `NodeIDAbsentError`) to enforce tree integrity.
- **Extensibility**: Pass a custom `node_class` to the `Tree` constructor and use `add_node()` to insert specialized node types.

## Frequently Asked Questions

### What is the difference between `create_node()` and `add_node()` in treelib?

`create_node()` instantiates a new `Node` object internally and immediately adds it to the tree, accepting parameters like `tag`, `identifier`, and `parent`. `add_node()` requires you to construct the `Node` object yourself before passing it as an argument, which is necessary when using custom `Node` subclasses or when nodes are created by external factories. Both methods ultimately execute the same pointer-updating logic in [`treelib/tree.py`](https://github.com/caesar0301/treelib/blob/main/treelib/tree.py).

### Can I add a node without specifying a parent in treelib?

Yes, but only for the first node in an empty tree. When you call `create_node()` or `add_node()` with `parent=None`, `treelib` checks if the tree is empty (line 825 in [`treelib/tree.py`](https://github.com/caesar0301/treelib/blob/main/treelib/tree.py)). If the tree already has a root, the library raises `MultipleRootError` from [`treelib/exceptions.py`](https://github.com/caesar0301/treelib/blob/main/treelib/exceptions.py) to prevent creating a second root node.

### How do I use a custom Node subclass when adding nodes to a treelib tree?

First, subclass `Node` from `treelib.node` to add your custom attributes or methods. Then, pass your subclass as the `node_class` parameter when initializing the `Tree` (line 69 in [`treelib/tree.py`](https://github.com/caesar0301/treelib/blob/main/treelib/tree.py)). Finally, use `add_node()` to insert instances of your custom class, as `create_node()` will also respect the `node_class` setting but `add_node()` gives you full control over the instantiation process.

### What happens if I try to add a node with a duplicate identifier in treelib?

The library raises `DuplicatedNodeIdError` defined in [`treelib/exceptions.py`](https://github.com/caesar0301/treelib/blob/main/treelib/exceptions.py). This check occurs in `add_node()` at line 998 of [`treelib/tree.py`](https://github.com/caesar0301/treelib/blob/main/treelib/tree.py) before any pointer updates are performed. Each node in a tree must have a unique identifier to maintain the integrity of the bidirectional pointer structure managed by `__update_fpointer` and `__update_bpointer`.