AlgoInsight

Q&A

How to create and manage subdomains in Laravel applications

By AlgoInsight Team2026-06-07laravelnetworkingphp

Overview

Subdomain routing lets one Laravel app serve different content or tenants based on the subdomain in the URL. Laravel matches the request's host against domain patterns you define, can extract a dynamic part as a parameter, and routes accordingly. It's the backbone of multi-tenant SaaS where each customer gets their-name.yourapp.com.

graph TD
    A["Request: tenant1.example.com"] --> B["Route::domain('{account}.example.com')"]
    B --> C[Capture account = 'tenant1']
    C --> D[Pass to controller / middleware]
    D --> E[Serve tenant-specific data]
    style B fill:#1e1b4b,color:#fff

Static Subdomain

Route a fixed subdomain to specific routes:

use Illuminate\Support\Facades\Route;

Route::domain('admin.example.com')->group(function () {
    Route::get('/', [AdminController::class, 'dashboard']);
    Route::get('/users', [AdminController::class, 'users']);
});

Requests to admin.example.com hit these routes; others don't.

Dynamic Subdomain (multi-tenant)

Capture the subdomain as a parameter with {}:

Route::domain('{account}.example.com')->group(function () {
    Route::get('/', function (string $account) {
        return "Welcome to the {$account} workspace";
    });
    Route::get('/dashboard', [DashboardController::class, 'show']);
});

The {account} value is injected as the first argument to route closures/controllers (before other route parameters):

public function show(string $account)
{
    $tenant = Tenant::where('slug', $account)->firstOrFail();
    // load tenant-scoped data
}

Resolving the Tenant via Middleware

For multi-tenancy, centralize tenant resolution in middleware so every route is scoped consistently:

class IdentifyTenant
{
    public function handle($request, Closure $next)
    {
        $account = $request->route('account');
        $tenant = Tenant::where('slug', $account)->firstOrFail();
        app()->instance('currentTenant', $tenant);   // make it available app-wide
        return $next($request);
    }
}
Route::domain('{account}.example.com')
    ->middleware(IdentifyTenant::class)
    ->group(function () { /* tenant routes */ });

DNS and Local Setup

Routing only works if requests actually reach your app under those hosts:

Generating URLs to Subdomains

When defining named routes inside a domain group, route URL generation includes the domain parameter:

Route::domain('{account}.example.com')->group(function () {
    Route::get('/billing', [BillingController::class, 'index'])->name('billing');
});
// route('billing', ['account' => 'tenant1']) → http://tenant1.example.com/billing

Packages for Serious Multi-Tenancy

For full SaaS multi-tenancy (separate databases per tenant, tenant-aware queries, etc.), dedicated packages like stancl/tenancy or spatie/laravel-multitenancy build on this routing and handle database switching, caching, and isolation. Mention them when the scope is real multi-tenancy rather than a couple of subdomains.

Why This Matters in Interviews

Laravel interviews use this to test routing depth and multi-tenancy awareness. Key points: Route::domain(...) with a {param} captures the subdomain, which is passed as the first controller/closure argument; middleware is the clean place to resolve and scope the tenant; and routing requires matching wildcard DNS (and TLS) to actually deliver requests. Knowing that real multi-tenancy uses dedicated packages for DB isolation shows practical scope awareness.

Common Pitfalls

References

More answers