How to Make Categories Inside Categories in Laravel (Unlimited Levels)

Sometimes in your Laravel app, you need to create categories that can have subcategories. And those subcategories can also have more subcategories. This is called nested categories, and it can go to any level — 2, 3, 5, or even more.
In this post, I will show you how to create this in a clean and simple way using Laravel.
Problem Example
You are building a blog or an online shop.
Category: Programming
Subcategory: PHP
Subcategory: Laravel
- Subcategory: Livewire
This is what we call a tree structure — one item has children, and those children have more children.
Step 1: Create Database Table
We will use a very simple structure. Just add a parent_id column in your categories table. This is called the Adjacency List method.
Table Example
id | name | parent_id |
1 | Programming | NULL |
2 | PHP | 1 |
3 | Laravel | 2 |
4 | Vue.js | 1 |
5 | Livewire | 3 |
This means:
Programming is a top-level category (no parent).
PHP is a child of Programming.
Laravel is a child of PHP.
Livewire is a child of Laravel.
Step 2: Laravel Model
In your Category.php model, define two relationships.
class Category extends Model
{
public function parent()
{
return $this->belongsTo(Category::class, 'parent_id');
}
public function children()
{
return $this->hasMany(Category::class, 'parent_id');
}
}
This helps you get the parent and children of any category easily.
Step 3: Recursive Relationship
To go deep into children of children, add a recursive function like this:
public function childrenRecursive()
{
return $this->children()->with('childrenRecursive');
}
Now you can get all levels of subcategories.
Step 4: Get Tree in Controller
In your controller, get only the top-level categories with all their children:
$categories = Category::with('childrenRecursive')->whereNull('parent_id')->get();
Step 5: Show in Blade View
In your main Blade file:
<ul>
@foreach($categories as $category)
<li>
{{ $category->name }}
@if($category->childrenRecursive->count())
@include('partials.category-children', ['children' => $category->childrenRecursive])
@endif
</li>
@endforeach
</ul>
Create a file called partials/category-children.blade.php:
<ul>
@foreach($children as $child)
<li>
{{ $child->name }}
@if($child->childrenRecursive->count())
@include('partials.category-children', ['children' => $child->childrenRecursive])
@endif
</li>
@endforeach
</ul>
This will show all categories in a nice tree view — no matter how many levels deep.
Summary Table
Method | Easy to use | Good for small projects | Needs a package |
Adjacency List | Yes | Yes | No |
Nested Set | No | No (good for large apps) | Yes |
Materialized Path | No | Sometimes | No |
We used the Adjacency List, which is the easiest and works well for most apps.
Final Words
If you are a beginner or working on a small to medium project, this method is best. It is simple and works well with Laravel Eloquent.
Later, if your app grows, you can explore more advanced methods like nested sets or materialized paths.
Let me know if you need help with code or want me to write about showing this in Vue or Livewire.
Subscribe to my newsletter
Read articles from Rameez Karamat Bhatti directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Rameez Karamat Bhatti
Rameez Karamat Bhatti
I am a full-stack developer currently working with PHP, Laravel, Tailwind CSS, and Livewire. I also work extensively with Inertia.js to build seamless single-page applications using Vue.js and Laravel. I have experience building reactive frontends with Vue.js and React, and robust backends with REST APIs. I am highly proficient in MySQL, MongoDB, and also comfortable working with PostgreSQL for relational data projects. My focus is on clean, scalable code and building user-focused digital products.