How to set dynamic route prefix in Laravel?
Stefan Bogdanescu
Founder & Senior Architect · 2026-06-29
How to Set Dynamic Route Prefixes in Laravel: Mastering Locale-Aware Routing
Building applications with multiple locales is a common requirement for global reach, and structuring your URLs accordingly—such as using /en/home versus /fr/home—is essential for SEO and user experience. The challenge you've encountered, regarding dynamically binding route prefixes based on session data within web.php, highlights a common friction point when mixing runtime state (like session data) with static file definitions in Laravel.
As a senior developer, I understand the desire to keep routing logic clean and dynamic. Let’s dive into why the direct approach you explored is tricky, and how we can solve this elegantly using Laravel's core features.
The Conundrum: Session State vs. Route Definition
You are absolutely correct in identifying the conundrum. The web.php file is parsed very early in the application lifecycle. While you can access session data via helper functions like session('key'), relying on this inside the route definition file to determine the structure of the routes before the request context is fully established presents a problem.
The core issue is that route definitions are typically static declarations. If we try to read session data directly in an outer scope, it often fails because the necessary context isn't yet fully available for global route registration. We need a mechanism that runs after the basic application state is loaded but before the routes are finalized, or a structure that delegates this decision-making.
The Solution: Dynamic Route Grouping with Middleware and Route Files
The most robust and idiomatic Laravel way to handle locale-aware routing is not to dynamically change the prefix inside web.php, but rather to use Route Groups combined with dynamic route files or middleware to manage these prefixes cleanly. This keeps your route definitions organized and leverages Laravel’s built-in structure, which aligns perfectly with principles discussed at sites like laravelcompany.com.
Instead of trying to inject the locale into the base path directly in web.php, we define a structure that allows us to map these dynamic prefixes easily.
Step 1: Define Locale-Specific Routes in Separate Files
We can separate our routes based on the locale. This keeps the logic clean and manageable, making it easy to scale as you add more languages.
Create separate route files for each locale (e.g., routes/en.php, routes/fr.php):
routes/en.php
use Illuminate\Support\Facades\Route;
// Routes for English locale
Route::prefix('en')->group(function () {
Route::get('/home', function () {
return 'Welcome Home in English!';
});
Route::get('/about', function () {
return 'About Us (EN)';
});
});
routes/fr.php
use Illuminate\Support\Facades\Route;
// Routes for French locale
Route::prefix('fr')->group(function () {
Route::get('/home', function () {
return 'Accueil en Français!';
});
Route::get('/about', function () {
return 'À Propos (FR)';
});
});
Step 2: Dynamic Routing via a Central Entry Point
Now, in your main web.php file, you no longer need to manually define every route. You can leverage the session data to dynamically load these locale files or use middleware to determine which set of routes applies.
A cleaner approach is to define a single entry point and let the routing structure handle the prefixing based on the request context (which is often determined by a subdomain or path segment).
If you must read the session, you can do so in a Service Provider that binds a dynamic route definition mechanism. For example, when your application boots, you check session('locale') and register routes accordingly.
// Example concept within AppServiceProvider.php (Illustrative)
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Session;
public function boot()
{
$locale = Session::get('locale', 'en'); // Default to English if locale is missing
// Dynamically load routes based on session data
if ($locale === 'fr') {
require base_path('routes/fr.php');
} else {
require base_path('routes/en.php');
}
}
This pattern ensures that the route file loading happens after the application context is established, solving your initial problem of accessing session data for dynamic routing decisions within the framework's flow.
Conclusion
Dynamically setting route prefixes based on user locale requires moving away from static definitions in web.php and embracing Laravel’s structure through Route Grouping and dynamic loading mechanisms like Service Providers. By separating your routes by locale, you create a system that is highly scalable, maintainable, and adheres to modern Laravel best practices. This approach ensures that your application remains flexible, regardless of how many languages you introduce in the future.