Managing route definitions in a large Laravel application can quickly become overwhelmingโespecially when dealing with complex modules like admissions, academics, and user management.
To ensure long-term maintainability, I recently refactored our admin route setup into a well-structured and modular format.
In this post, Iโll share how we transitioned from a monolithic route group to a fully modular setup and what benefits it brings.
๐ง The Challenge: Growing Route Complexity
Initially, all admin-related routes were grouped inside a massive closure in web.php. This approach worked fine at first, but as the system evolved:
- The route file grew to hundreds of lines.
- Unrelated concerns (e.g., admission vs programme) were tangled together.
- Collaboration became error-prone due to constant merge conflicts.
We needed a better structure.
๐งญ The Strategy: Structured Route Definitions
Instead of stuffing everything into web.php, we organised our routes into dedicated files under a routes/web/admin directory.
โ Step 1: Central Admin Route Loader
// routes/web/admin.php
use Illuminate\Support\Facades\Route;
Route::group([
'middleware' => ['is_admin', 'auth', 'verified'],
'prefix' => 'admin', 'as' => 'admin.',
], function () {
require_all_in(base_path('routes/web/admin/*.php'));
});
This loads all files matching admin/*.php, keeping the main file clean.
โ Step 2: Nested Setup Group
Setup-related routes are more detailed, so we pushed them further into a subdirectory:
// routes/web/admin/setup.php
use Illuminate\Support\Facades\Route;
Route::group(['prefix' => 'setup', 'as' => 'setups.'], function () {
require_all_in(base_path('routes/web/admin/setup/*.php'));
});
This allows better organisation and logical grouping of setup domains like CRM, programme, admission, etc.
๐ Final Directory Layout
routes/
โโโ web/
โโโ admin.php # Loads all admin route groups
โโโ admin/
โโโ academics.php
โโโ admissions.php
โโโ prospective-student.php
โโโ users.php
โโโ impersonate.php
โโโ governance.php
โโโ excel.php
โโโ profile.php
โโโ misc.php
โโโ document-template.php
โโโ letter.php
โโโ setup.php # Loads all setup submodules
โโโ setup/
โโโ admission.php
โโโ crm.php
โโโ programme.php
โโโ residential.php
โโโ student-record.php
โโโ common.php
๐ Verifying the Structure
After restructuring, I dumped the route list before and after, then compared them programmatically.
Outcome:
- โ No routes were removed.
- โ No duplication or misrouting occurred.
- โ Route paths, names, and middleware stacks stayed intact.
๐ Bonus
Dump routes before and after refactor
You may wan to dump the before refactor routes and after refactor the routes:
php artisan route:list --json > routes/route-ori.json
Then after refactor:
php artisan route:list --json > routes/route-refactor.json
Grab those two JSON files, and dump to ChatGPT / Claude to help you analyse and compare differences in both route files.
If there's missing routes, you may double check and add back those missing routes.
The require_all_in() Helper
To autoload all files in a directory, I used this helper:
function require_all_in($path) {
foreach (glob($path) as $filename) {
require_once $filename;
}
}
This keeps each route group isolated and ensures automatic loading without manual imports.
๐ Why This Matters
This restructuring significantly improved:
- Readability: Route responsibilities are clearly separated.
- Modularity: Easy to locate and modify specific feature routes.
- Team Collaboration: Developers can work independently in their modules.
- Future Growth: Adding new route groups doesnโt clutter core files.
๐ Conclusion
A well-structured route directory makes a huge difference in large Laravel applications. If you're managing more than a few modules, modularising and grouping your routes should be a standard practice.
Itโs a small change with massive long-term impact.
Top comments (0)