Rutas avanzadas — grupos, prefijos, nombres
Aprende a organizar las rutas de Laravel con grupos, prefijos y nombres para mantener tu archivo de rutas limpio y escalable.
Por qué necesitas rutas avanzadas
Cuando una aplicación crece, el archivo routes/web.php puede convertirse en un caos. Decenas o cientos de rutas sin organización hacen que sea difícil encontrar lo que buscas, y mucho peor, dificultan cambiar las URLs en el futuro sin romper otras partes del código.
Laravel ofrece herramientas muy potentes para organizar las rutas: grupos, prefijos, nombres y middlewares (estos últimos en la siguiente lección). Dominar estas herramientas es fundamental para mantener proyectos grandes.
Nombrar Rutas
Lo primero que deberías hacer es darle un nombre a cada ruta. En lugar de generar URLs con cadenas de texto directas, usas el nombre:
// Sin nombre (problemático)
Route::get('/productos', [ProductoController::class, 'index']);
// Con nombre (recomendado)
Route::get('/productos', [ProductoController::class, 'index'])->name('productos.index');
En tus vistas y controladores usas la función route():
// En Blade
<a href="{{ route('productos.index') }}">Ver productos</a>
// En un controlador
return redirect()->route('productos.index');
Si algún día decides cambiar /productos por /catalogo, solo modificas la definición de la ruta. Todos los route('productos.index') en el código seguirán funcionando sin tocar nada más.
Pasar Parámetros a Rutas Nombradas
Cuando la ruta tiene parámetros, los pasas como segundo argumento:
Route::get('/productos/{id}', [ProductoController::class, 'show'])->name('productos.show');
Route::get('/productos/{id}/edit', [ProductoController::class, 'edit'])->name('productos.edit');
// Con un parámetro
<a href="{{ route('productos.show', ['id' => $producto->id]) }}">Ver</a>
// Forma abreviada (valor directamente)
<a href="{{ route('productos.show', $producto->id) }}">Ver</a>
// Con múltiples parámetros
<a href="{{ route('productos.comentarios.show', ['producto' => 1, 'comentario' => 5]) }}">
Ver comentario
</a>
Agrupar Rutas con Route::group
El método Route::group te permite aplicar atributos comunes a un conjunto de rutas:
Route::group(['prefix' => 'admin', 'as' => 'admin.'], function () {
Route::get('/dashboard', [AdminController::class, 'dashboard'])->name('dashboard');
Route::get('/usuarios', [UsuarioController::class, 'index'])->name('usuarios');
Route::get('/productos', [ProductoController::class, 'index'])->name('productos');
});
En este ejemplo:
- Todas las rutas tendrán el prefijo
/adminen la URL. - Todos los nombres de ruta empezarán con
admin.. - El nombre completo del dashboard sería
admin.dashboard.
Prefijos de URL
Si solo necesitas un prefijo en la URL sin más atributos, la sintaxis encadenada es más limpia:
Route::prefix('admin')->group(function () {
Route::get('/dashboard', [AdminController::class, 'dashboard']);
// URL resultante: /admin/dashboard
Route::get('/usuarios', [UsuarioController::class, 'index']);
// URL resultante: /admin/usuarios
Route::get('/configuracion', [ConfigController::class, 'index']);
// URL resultante: /admin/configuracion
});
Prefijos de Nombres con name()
Para que los nombres de ruta también tengan un prefijo común:
Route::name('admin.')->prefix('admin')->group(function () {
Route::get('/dashboard', [AdminController::class, 'dashboard'])->name('dashboard');
// Nombre completo: admin.dashboard
Route::get('/usuarios', [UsuarioController::class, 'index'])->name('usuarios');
// Nombre completo: admin.usuarios
});
Ahora en tus vistas:
<a href="{{ route('admin.dashboard') }}">Dashboard</a>
<a href="{{ route('admin.usuarios') }}">Gestión de usuarios</a>
Grupos Anidados
Los grupos se pueden anidar para estructuras más complejas:
Route::prefix('admin')->name('admin.')->group(function () {
// Rutas generales de admin
Route::get('/dashboard', [AdminController::class, 'dashboard'])->name('dashboard');
// Sub-grupo para la tienda
Route::prefix('tienda')->name('tienda.')->group(function () {
Route::get('/productos', [ProductoController::class, 'index'])->name('productos');
// URL: /admin/tienda/productos
// Nombre: admin.tienda.productos
Route::get('/categorias', [CategoriaController::class, 'index'])->name('categorias');
// URL: /admin/tienda/categorias
// Nombre: admin.tienda.categorias
});
// Sub-grupo para usuarios
Route::prefix('usuarios')->name('usuarios.')->group(function () {
Route::get('/', [UsuarioController::class, 'index'])->name('index');
// URL: /admin/usuarios
// Nombre: admin.usuarios.index
Route::get('/{id}', [UsuarioController::class, 'show'])->name('show');
// URL: /admin/usuarios/{id}
// Nombre: admin.usuarios.show
});
});
Restricciones en Parámetros de Rutas
Puedes indicar qué formato deben tener los parámetros de ruta usando expresiones regulares:
// Solo números
Route::get('/productos/{id}', [ProductoController::class, 'show'])
->where('id', '[0-9]+')
->name('productos.show');
// Solo letras y guiones (slug)
Route::get('/blog/{slug}', [BlogController::class, 'show'])
->where('slug', '[a-z0-9-]+')
->name('blog.show');
// Varios parámetros
Route::get('/usuarios/{id}/pedidos/{pedido}', [PedidoController::class, 'show'])
->where(['id' => '[0-9]+', 'pedido' => '[0-9]+']);
Laravel también tiene métodos de ayuda para restricciones comunes:
Route::get('/productos/{id}', [ProductoController::class, 'show'])
->whereNumber('id');
Route::get('/blog/{slug}', [BlogController::class, 'show'])
->whereAlphaNumeric('slug');
Rutas Fallback
Si ninguna ruta coincide con la URL, Laravel devuelve un 404. Puedes personalizar ese comportamiento con una ruta fallback:
Route::fallback(function () {
return view('errores.404');
});
Coloca siempre la ruta fallback al final del archivo de rutas.
Rutas con Namespaces de Controladores
En proyectos grandes, puedes organizar los controladores en subdirectorios y usar el método namespace en los grupos para evitar imports repetitivos:
// Sin namespace en el grupo (tienes que importar cada controlador)
use App\Http\Controllers\Admin\DashboardController;
use App\Http\Controllers\Admin\UsuarioController;
Route::prefix('admin')->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index']);
Route::get('/usuarios', [UsuarioController::class, 'index']);
});
// Con namespace en el grupo (más limpio para grupos grandes)
// Nota: en Laravel 8+ se prefiere usar los imports directos
Organizar Rutas en Múltiples Archivos
Cuando tu aplicación tiene muchas rutas, puedes separarlas en múltiples archivos y cargarlos desde RouteServiceProvider o directamente desde web.php:
// routes/web.php
require __DIR__.'/admin.php';
require __DIR__.'/api-web.php';
// routes/admin.php
use App\Http\Controllers\Admin\DashboardController;
use App\Http\Controllers\Admin\UsuarioController;
Route::prefix('admin')->name('admin.')->middleware('auth')->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard');
Route::resource('usuarios', UsuarioController::class);
});
Verificar las Rutas Registradas
Una de las herramientas más útiles de Artisan para trabajar con rutas:
# Ver todas las rutas
php artisan route:list
# Filtrar por nombre
php artisan route:list --name=admin
# Filtrar por método HTTP
php artisan route:list --method=GET
# Ver solo rutas con un path específico
php artisan route:list --path=productos
Rutas con Parámetros Opcionales
A veces un parámetro es opcional. Se indica con ? y se debe definir un valor por defecto en el controlador:
Route::get('/usuarios/{nombre?}', function (?string $nombre = 'invitado') {
return "Hola, {$nombre}";
})->name('saludo');
// /usuarios → "Hola, invitado"
// /usuarios/Juan → "Hola, Juan"
Resumen
Las rutas avanzadas de Laravel te dan el control total sobre cómo está estructurada tu aplicación. Usar nombres en las rutas protege tu código frente a cambios de URL. Los grupos con prefijos y nombres anidados mantienen el archivo de rutas organizado y legible. Invertir tiempo en organizar bien las rutas desde el principio te ahorrará muchos dolores de cabeza cuando el proyecto crezca.
Pon a prueba lo aprendido
Responde las preguntas para comprobar que has entendido los conceptos clave.
1. ¿Cuál es la forma correcta de aplicar un prefijo "/admin" a un grupo de rutas?
2. ¿Cómo se genera una URL usando el nombre de una ruta en Blade?
3. ¿Qué método se usa para asignar un nombre a una ruta en Laravel?