Laravel Wildcard Domains: A Subdomain for Each Client

Posted January 30, 2021 in Laravel

Building modern multi-tenancy applications in Laravel, such as a SaaS, you might want each client to pick their custom subdomain giving them better branding.

Setting up a route group for a wildcard subdomain in Laravel is easy and can be grouped around your existing routes:

Route::domain('{client}.my-app.com')->group(function(() {
  Route::resource('users', UsersController::class);
  // The rest of your routes
});

What if you want to sign users into their setup based on the URL?

No problem! Create a clients table and link all users to it:

<?php

use App\Client;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateClientsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('clients', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('clients');
    }
}

Add APP_ROOT_DOMAIN to your .env-file like this

APP_ROOT_DOMAIN=my-app.com

In your model class for the clients-table add this static method to retrieve the client based on subdomain:

/**
 * Return client based on current subdomain.
 * 
 * @return Client
 */
public static function subdomain(): Client
{
    return Client::where('subdomain', strtolower(str_replace('.'. env('APP_ROOT_DOMAIN'), '', request()->getHost())))->firstOrFail();
}

Now you can query users or other related data like this:

User::where('client_id', Client::subdomain()->id)

But what about dev environment?

Your dev environment is covered too. Out of the box it works for our static client method.

For the route group, we can benefit from the .env variable:

Route::domain('{client}.'. env('APP_ROOT_DOMAIN'))->group