JSON
Recursive Function
Hierarchical Data
Data Structures
Programming

Recursive function to create hierarchical JSON object?

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

If you have flat records with parent-child relationships and you want nested JSON, recursion is often the clearest solution. The basic idea is simple: find the children of the current node, build each child recursively, and stop when a node has no children.

A Common Input Shape

Suppose you start with rows like this:

javascript
1const items = [
2  { id: 1, name: "Root", parentId: null },
3  { id: 2, name: "Projects", parentId: 1 },
4  { id: 3, name: "Archive", parentId: 1 },
5  { id: 4, name: "2026", parentId: 2 },
6  { id: 5, name: "Images", parentId: 2 }
7];

This is flat data, but it describes a tree. The goal is to turn it into nested JSON with children arrays.

Recursive Tree Builder

Here is a straightforward recursive function in JavaScript:

javascript
1function buildTree(items, parentId = null) {
2  return items
3    .filter(item => item.parentId === parentId)
4    .map(item => ({
5      id: item.id,
6      name: item.name,
7      children: buildTree(items, item.id)
8    }));
9}
10
11const tree = buildTree(items);
12console.log(JSON.stringify(tree, null, 2));

This works because:

  • the base case happens naturally when no children are found
  • the recursive step builds each child's children array

The output is hierarchical JSON that mirrors the parent-child structure.

Why Recursion Fits the Problem

Hierarchical data is self-similar:

  • a root contains children
  • each child may contain children
  • each descendant follows the same rule

That is exactly the kind of structure recursion models well. The same function can process the top level and every nested level without special-case code for depth 1, depth 2, and so on.

Python Version

The same pattern works cleanly in Python:

python
1items = [
2    {"id": 1, "name": "Root", "parentId": None},
3    {"id": 2, "name": "Projects", "parentId": 1},
4    {"id": 3, "name": "Archive", "parentId": 1},
5    {"id": 4, "name": "2026", "parentId": 2},
6]
7
8
9def build_tree(rows, parent_id=None):
10    return [
11        {
12            "id": row["id"],
13            "name": row["name"],
14            "children": build_tree(rows, row["id"]),
15        }
16        for row in rows
17        if row["parentId"] == parent_id
18    ]
19
20
21print(build_tree(items))

This is the same algorithm expressed in a different language: select children, recurse, stop when no children exist.

Improving Performance for Large Trees

The simple version scans the full list at every recursion level. That is easy to read but not ideal for large datasets.

A better approach is to pre-group rows by parentId:

javascript
1function indexByParent(items) {
2  const map = new Map();
3
4  for (const item of items) {
5    const key = item.parentId;
6    if (!map.has(key)) {
7      map.set(key, []);
8    }
9    map.get(key).push(item);
10  }
11
12  return map;
13}
14
15function buildTreeFast(index, parentId = null) {
16  const children = index.get(parentId) || [];
17  return children.map(item => ({
18    id: item.id,
19    name: item.name,
20    children: buildTreeFast(index, item.id)
21  }));
22}
23
24const index = indexByParent(items);
25console.log(JSON.stringify(buildTreeFast(index), null, 2));

This keeps recursion but avoids repeated full-list filtering.

Common Pitfalls

The most common mistake is not defining a real base case. Even though the base case can be implicit, the data still needs to terminate cleanly with nodes that have no children.

Another issue is forgetting to guard against cycles. If the input data contains an accidental parent loop, a naive recursive function can recurse forever.

A third pitfall is assuming the root always has parentId = null. Some systems use 0, an empty string, or a separate root marker instead. Match the function to the actual data model.

Finally, for very large trees, repeated filtering can become expensive. Pre-indexing by parent is usually the easiest performance improvement.

Summary

  • Recursive tree building is a natural fit for hierarchical JSON generation.
  • The core pattern is filter children, map them, and recurse into each child.
  • Flat parent-child records can be transformed into nested JSON cleanly with one function.
  • Pre-grouping rows by parentId improves performance on larger datasets.
  • Watch for cycles, root-convention mismatches, and missing termination conditions.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.