Courses

Laravel 12 Multi-Tenancy: All You Need To Know

Making DB Structure Changes for Tenants

Summary of this lesson:
- Managing database schema changes for multiple tenant databases
- Using tenant-specific migration folders
- Running migrations across all tenant databases with tenants:migrate command

In this course, we have covered all the basic features and all the primary use cases for packages for multi-tenancy. Let's spend some time on advanced features or what else we can do after installing the stancl/tenancy package.

Based on the demo project, I will continue working on that for upcoming lessons and will introduce a few more features and show how it works in a bit advanced way.

In this lesson, what do you do if you want to add something to the database structure of tenants?

For example, you have a task CRUD, and every tenant has its own database, and you want to add a field there. Let's add a description column to the tasks.


The package adds tenant migrations into the database/migrations/tenant folder. Then, instead of running the Artisan command migrate, we must run the tenants:migrate command.

So, first, the Migration.

php artisan make:migration "add description to tasks table" --path=database/migrations/tenant

database/migrations/tenant/xxx_add_description_to_tasks_table.php:

Schema::table('tasks', function (Blueprint $table) {
$table->string('description')->nullable();
});

app/Models/Task.php:

class Task extends Model
{
protected $fillable = [
'name',
'project_id',
'description',
];
 
// ...
}

Then, we add those fields to the create and edit forms.

resources/views/tasks/create.blade.php:

// ...
 
<div class="mt-4">
<x-input-label for="description" :value="__('Description')"/>
 
<x-text-input id="description" class="block mt-1 w-full" type="text" name="description" :value="old('description')" />
 
<x-input-error :messages="$errors->get('description')" class="mt-2" />
</div>
 
// ...

resources/views/tasks/edit.blade.php:

// ...
 
<div class="mt-4">
<x-input-label for="description" :value="__('Description')"/>
 
<x-text-input id="description" class="block mt-1 w-full" type="text" name="description" :value="$task->description" />
 
<x-input-error :messages="$errors->get('description')" class="mt-2" />
</div>
 
// ...

And let's show the description in the table.

resources/views/tasks/index.blade.php:

// ...
 
<th scope="col" class="px-6 py-3 text-left">
Description
</th>
 
// ...
 
<td class="px-6 py-4 font-medium text-gray-900 dark:text-white whitespace-nowrap">
{{ $task->description }}
</td>
// ...

We must add a description column to the Form Request.

app/Http/Requests/StoreTaskRequest.php:

class StoreTaskRequest extends FormRequest
{
// ...
 
public function rules(): array
{
return [
'name' => 'required',
'project_id' => 'required',
'description' => 'nullable|string',
];
}
}

app/Http/Requests/UpdateTaskRequest.php:

class UpdateTaskRequest extends FormRequest
{
// ...
 
public function rules(): array
{
return [
'name' => 'required',
'project_id' => 'required',
'description' => 'nullable|string',
];
}
}

If we tried to add a description, we would receive an error Unknown column 'description'... because we haven't run the migrations yet.

However, we must run migrations to each tenant's database. Instead of a regular Artisan command migrate, now we must use the command provided by the package tenants:migrate. This command will run all the migrations from a database/migrations/tenant folder.

When running the tenants:migrate command, we can see in the output migrations are run to each tenant.

Now, we can add and edit descriptions for a task.


This is how you can make any changes to your database structure for all the tenants. You generate the migration in the tenant subfolder and then run the tenants:migrate Artisan command to process the changes into all tenants.

You can find the source code for this lesson on GitHub.

Previous: Multiple DBs: spatie / multi-tenancy

No comments yet…

avatar
You can use Markdown