SlideShare a Scribd company logo
Multi-tenant Laravel
How to build a SaaS application with separated databases
Intro
Peter Mein
Lead Developer at Rapide Internet
Laravel
API’s
DevOps
K8’s
At the controls:
Lucas van der Have
Senior Developer bij DossierData
Saas? Tenants?
What is SaaS?
What is a tenant?
Saas? Tenants?
What is SaaS?
What is a tenant?
Saas? Tenants?
What is SaaS?
What is a tenant?
The principle of multi-tenancy is about a single piece of software
serving multiple tenants.
Why?
To maintain and service individual customer better
Examples
● CTIP 120+ tables, 50+ tenants, 20m+ geoobjects, total 50gb, single database
● DossierData, 150+ tables, 200+ tenants averaging 1Gb - 5Gb per db
● MKA, 100+ tables, 200+ tenants, 2m+ chatberichten
Multi-tenant !== Multi-website
Multi-tenant
1 application codebase serving multiple customers with a distinct dataset
i.e. GMail, Facebook or LinkedIn
Multi-website
1 application codebase serving multiple websites/fronts
i.e. Magento
Single database
Multi-tenant
Database Layout
Example of table structure
Master database RO
Shared database RW
Tenant database RW / RO
Separated database
#deepdive
Request lifecycle
- Request
- Middleware
- Setup tenant connection
- Controller
- Call models from the tenant db
- Call models from a shared or master database
- Inter database relations
- Fire a tenant event
- Return response
Setup tenant connection
Determine tenant
Encryption
Changing configs on the fly
Setup tenant connection
Determine tenant
Encryption
Changing configs on the fly
Setup tenant connection
public function getTenant()
{
$subdomain = $this->getSubdomain();
if ($this->tenant !== null) {
return $this->tenant;
}
return $this->tenant = $this->tenantRepository->findBySubdomain($subdomain);
}
Services/TenantService.php
Setup tenant connection
Determine tenant
Encryption
Changing configs on the fly
Setup tenant connection
private function getDatabaseCredentialsByTenant(Tenant $tenant): array
{
return [
'hostname' => $tenant->db_host,
'database' => $this->encrypter->decrypt($tenant->db_name),
'username' => $this->encrypter->decrypt($tenant->db_user),
'password' => $this->encrypter->decrypt($tenant->db_pass),
];
}
Services/TenantService.php
Setup tenant connection
Determine tenant
Encryption
Changing configs on the fly
Setup tenant connection
public function connect(Tenant $tenant = null): bool
{
if ($tenant === null) {
return false;
}
list($hostname, $database, $username, $password) = $this->getDatabaseCredentialsByTenant($tenant);
// Update tenant connection configs
$this->updateConnectionDetails('tenant_database', $hostname, $database, $username, $password);
// Set to shared hostname to same as tenant database, necessary for migration to Galera
$this->updateConnectionDetails('shared_database', $hostname);
$this->reconnectConnection('shared_database');
$this->connection = $this->reconnectConnection('mysql');
return true;
}
Services/ConnectionService.php
Setup tenant connection
protected function updateConnectionDetails($connection, $hostname, $database = null, $username = null, $password = null)
{
$settingKey = sprintf('database.connections.%s', $connection);
config(sprintf('%s.host', $settingKey), $hostname);
if ($database !== null) {
config(sprintf('%s.database', $settingKey), $database);
}
if ($username !== null) {
config(sprintf('%s.username', $settingKey), $username);
}
if ($password !== null) {
config(sprintf('%s.password', $settingKey), $password);
}
}
Services/ConnectionService.php
Call model from the tenant db
- Primary connection
- Call model as normally
i.e.
- Model::find(1);
Call model from shared or master db
- Switch connection of a model or set the default connection on the model
- Retrieve the model using eloquent
Call model from shared or master db
class Permission extends Model
{
public function getConnectionName()
{
return 'shared_database';
}
protected $fillable = [
'name',
'description',
'policy'
];
}
Models/Permission.php
Inter database relations
- A Role has many Permissions
- Permissions are stored in shared db
- Laravel limitations and how to fix them
- Direction of relations
SELECT * FROM tenant_database.users AS u
JOIN tenant_database.users_roles AS ur ON u.id = ur.user_id
JOIN shared_database.roles AS r ON ur.role_id = r.id
WHERE u.id = 1;
Call model from shared or master db
class Permission extends Model
{
...
private function getTableNameForConnection($table, $connection = null)
{
return vsprintf('%s.%s', [$this->getDatabaseNameForConnection($connection), $table]);
}
public function roles()
{
return $this->belongsToMany(
AppModelsRole::class,
$this->getTableNameForConnection('role_permissions', 'tenant_database'),
'permission_id',
'role_id'
);
}
...
}
Models/Permission.php
Fire an event
- Only a problem on Async listeners
- Needs a tenant to run
Fire an event
abstract class TenantEvent extends Event
{
public function __construct()
{
if (($tenant = $this->getTenantService()->getTenant()) instanceof Tenant) {
$this->setTenant($tenant);
} else {
throw new MissingTenantException();
}
}
public function __sleep()
{
// Unset tenant model for serialization
$this->tenant = null;
// Continue with sleep
return parent::__sleep();
}
public function __wakeup()
{
// Fetch the tenant by id
$this->tenant = $this->getTenantService()->find($this->tenantId);
$this->tenantId = $this->tenant->id;
// Initialize tenant database connection
$this->getTenantManager()->connect($this->tenant);
// Continue with wake up
parent::__wakeup();
}
}
Abstracts/TenantEvent.php
Warnings
Everything outside the request lifecycle requires manual tenant switching
Cache
Broadcast
Storage
Queues
Inter database relations and connections to be used
Cross connection transactions
Pro’s & Con’s
Backups per tenant
Easy recovery
GDPR
Scalability
Manageability (migrating to new db environment)
Overhead
Complexer logic for built in laravel functions:
- Commands
- Events
- Queues
- Broadcasting
Planning ahead
Server layout
Layer 4 load balancing
Packages
I don’t want to do this all by myself:
https://github.com/hyn/multi-tenant ★1143
https://github.com/orchestral/tenanti ★406
https://github.com/HipsterJazzbo/Landlord ★525
Andere onderwerpen
● Laravel API's and their limitations
● Strangling Laravel with react
● Deploying Laravel to production (With CI)
● Error handling in Laravel with channels and sentry
● Oauth2 implementation with passport (and what its missing)
● Laravel and Kubernetes
● Local development with Docker
● Broadcasting to the world
● Storage in the cloud, and efficient image retrieval (Thumbor and S3)
● Unit testing, Integration testing, Browser testing
● Package development and contributing to open source
● Modular laravel; simulate microservices
https://sli.do #F294
Questions?
Thank you

More Related Content

PDF
Cloud Migration Strategy and Best Practices
PPT
basics of cloud computing
PDF
F5_Active-Active Data Center.pdf
PDF
Cloud Computing Essentials
PPTX
WS-Addressing
PDF
Enterprise WAN Transformation: SD-WAN, SASE, and the Pandemic
PPTX
Cisco Identity Services Engine (ISE)
PPTX
Virtualization security for the cloud computing technology
Cloud Migration Strategy and Best Practices
basics of cloud computing
F5_Active-Active Data Center.pdf
Cloud Computing Essentials
WS-Addressing
Enterprise WAN Transformation: SD-WAN, SASE, and the Pandemic
Cisco Identity Services Engine (ISE)
Virtualization security for the cloud computing technology

What's hot (20)

PDF
DataPower API Gateway Performance Benchmarks
PDF
Cloud Security Governance
PDF
On Premise vs Cloud Computing | Cloud Certification Training | Edureka
PPT
Legal issues in cloud computing
PPTX
Cloud Computing Architecture
PPTX
Cloud Application Development – The Future is now
PDF
Apache Kafka, Tiered Storage and TensorFlow for Streaming Machine Learning wi...
PDF
FinOps@SC CH-Meetup.pdf
PPT
SaaS Presentation at SCIT Conference
PDF
Software-Defined WAN: A Real World Success Story
PPTX
How Apache Spark and Apache Hadoop are being used to keep banking regulators ...
PPTX
What is Virtualization and its types & Techniques.What is hypervisor and its ...
PPTX
RTI Support for FACE TSS
PPTX
Aws overview
PPTX
CORBA Component Model
PPTX
Introduction to Cloud Computing and Cloud Infrastructure
PPSX
Citrix Workspace Suite
PDF
DDD 구현기초 (거의 Final 버전)
PPT
Cloud and dynamic infrastructure
PDF
Unit 1 - mobile computing introduction
DataPower API Gateway Performance Benchmarks
Cloud Security Governance
On Premise vs Cloud Computing | Cloud Certification Training | Edureka
Legal issues in cloud computing
Cloud Computing Architecture
Cloud Application Development – The Future is now
Apache Kafka, Tiered Storage and TensorFlow for Streaming Machine Learning wi...
FinOps@SC CH-Meetup.pdf
SaaS Presentation at SCIT Conference
Software-Defined WAN: A Real World Success Story
How Apache Spark and Apache Hadoop are being used to keep banking regulators ...
What is Virtualization and its types & Techniques.What is hypervisor and its ...
RTI Support for FACE TSS
Aws overview
CORBA Component Model
Introduction to Cloud Computing and Cloud Infrastructure
Citrix Workspace Suite
DDD 구현기초 (거의 Final 버전)
Cloud and dynamic infrastructure
Unit 1 - mobile computing introduction
Ad

Similar to Multi tenant laravel (20)

KEY
Zend Framework Study@Tokyo #2
PDF
Developing Cacheable PHP Applications - PHP SP 2024
PDF
Facebook的缓存系统
PDF
4069180 Caching Performance Lessons From Facebook
PDF
REST more with json-api and fractal
PDF
Dependency Injection
PDF
Lithium: The Framework for People Who Hate Frameworks
KEY
PDF
How kris-writes-symfony-apps-london
PDF
Bootstrat REST APIs with Laravel 5
PDF
Osiąganie mądrej architektury z Symfony2
PDF
Zendcon 2007 Api Design
PDF
Doctrine For Beginners
PDF
Service discovery and configuration provisioning
PDF
What's New In Laravel 5
PDF
The Zen of Lithium
PDF
WordCamp San Francisco 2011: Transients, Caching, and the Complexities of Mul...
KEY
Phpne august-2012-symfony-components-friends
PDF
Dependency injection in Drupal 8
PDF
Why is crud a bad idea - focus on real scenarios
Zend Framework Study@Tokyo #2
Developing Cacheable PHP Applications - PHP SP 2024
Facebook的缓存系统
4069180 Caching Performance Lessons From Facebook
REST more with json-api and fractal
Dependency Injection
Lithium: The Framework for People Who Hate Frameworks
How kris-writes-symfony-apps-london
Bootstrat REST APIs with Laravel 5
Osiąganie mądrej architektury z Symfony2
Zendcon 2007 Api Design
Doctrine For Beginners
Service discovery and configuration provisioning
What's New In Laravel 5
The Zen of Lithium
WordCamp San Francisco 2011: Transients, Caching, and the Complexities of Mul...
Phpne august-2012-symfony-components-friends
Dependency injection in Drupal 8
Why is crud a bad idea - focus on real scenarios
Ad

Recently uploaded (20)

PDF
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
PDF
PTS Company Brochure 2025 (1).pdf.......
PDF
SAP S4 Hana Brochure 3 (PTS SYSTEMS AND SOLUTIONS)
PPTX
VVF-Customer-Presentation2025-Ver1.9.pptx
PPTX
CHAPTER 2 - PM Management and IT Context
PPTX
Reimagine Home Health with the Power of Agentic AI​
PPTX
L1 - Introduction to python Backend.pptx
PDF
Adobe Premiere Pro 2025 (v24.5.0.057) Crack free
PDF
System and Network Administration Chapter 2
PDF
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
PPTX
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
PDF
medical staffing services at VALiNTRY
PPTX
Transform Your Business with a Software ERP System
PPTX
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
PPTX
Operating system designcfffgfgggggggvggggggggg
PDF
How Creative Agencies Leverage Project Management Software.pdf
PDF
AI in Product Development-omnex systems
PDF
Wondershare Filmora 15 Crack With Activation Key [2025
PPTX
Essential Infomation Tech presentation.pptx
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
PTS Company Brochure 2025 (1).pdf.......
SAP S4 Hana Brochure 3 (PTS SYSTEMS AND SOLUTIONS)
VVF-Customer-Presentation2025-Ver1.9.pptx
CHAPTER 2 - PM Management and IT Context
Reimagine Home Health with the Power of Agentic AI​
L1 - Introduction to python Backend.pptx
Adobe Premiere Pro 2025 (v24.5.0.057) Crack free
System and Network Administration Chapter 2
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
medical staffing services at VALiNTRY
Transform Your Business with a Software ERP System
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
Operating system designcfffgfgggggggvggggggggg
How Creative Agencies Leverage Project Management Software.pdf
AI in Product Development-omnex systems
Wondershare Filmora 15 Crack With Activation Key [2025
Essential Infomation Tech presentation.pptx

Multi tenant laravel

  • 1. Multi-tenant Laravel How to build a SaaS application with separated databases
  • 2. Intro Peter Mein Lead Developer at Rapide Internet Laravel API’s DevOps K8’s At the controls: Lucas van der Have Senior Developer bij DossierData
  • 3. Saas? Tenants? What is SaaS? What is a tenant?
  • 4. Saas? Tenants? What is SaaS? What is a tenant?
  • 5. Saas? Tenants? What is SaaS? What is a tenant? The principle of multi-tenancy is about a single piece of software serving multiple tenants.
  • 6. Why? To maintain and service individual customer better Examples ● CTIP 120+ tables, 50+ tenants, 20m+ geoobjects, total 50gb, single database ● DossierData, 150+ tables, 200+ tenants averaging 1Gb - 5Gb per db ● MKA, 100+ tables, 200+ tenants, 2m+ chatberichten
  • 7. Multi-tenant !== Multi-website Multi-tenant 1 application codebase serving multiple customers with a distinct dataset i.e. GMail, Facebook or LinkedIn Multi-website 1 application codebase serving multiple websites/fronts i.e. Magento
  • 10. Database Layout Example of table structure Master database RO Shared database RW Tenant database RW / RO
  • 13. Request lifecycle - Request - Middleware - Setup tenant connection - Controller - Call models from the tenant db - Call models from a shared or master database - Inter database relations - Fire a tenant event - Return response
  • 14. Setup tenant connection Determine tenant Encryption Changing configs on the fly
  • 15. Setup tenant connection Determine tenant Encryption Changing configs on the fly
  • 16. Setup tenant connection public function getTenant() { $subdomain = $this->getSubdomain(); if ($this->tenant !== null) { return $this->tenant; } return $this->tenant = $this->tenantRepository->findBySubdomain($subdomain); } Services/TenantService.php
  • 17. Setup tenant connection Determine tenant Encryption Changing configs on the fly
  • 18. Setup tenant connection private function getDatabaseCredentialsByTenant(Tenant $tenant): array { return [ 'hostname' => $tenant->db_host, 'database' => $this->encrypter->decrypt($tenant->db_name), 'username' => $this->encrypter->decrypt($tenant->db_user), 'password' => $this->encrypter->decrypt($tenant->db_pass), ]; } Services/TenantService.php
  • 19. Setup tenant connection Determine tenant Encryption Changing configs on the fly
  • 20. Setup tenant connection public function connect(Tenant $tenant = null): bool { if ($tenant === null) { return false; } list($hostname, $database, $username, $password) = $this->getDatabaseCredentialsByTenant($tenant); // Update tenant connection configs $this->updateConnectionDetails('tenant_database', $hostname, $database, $username, $password); // Set to shared hostname to same as tenant database, necessary for migration to Galera $this->updateConnectionDetails('shared_database', $hostname); $this->reconnectConnection('shared_database'); $this->connection = $this->reconnectConnection('mysql'); return true; } Services/ConnectionService.php
  • 21. Setup tenant connection protected function updateConnectionDetails($connection, $hostname, $database = null, $username = null, $password = null) { $settingKey = sprintf('database.connections.%s', $connection); config(sprintf('%s.host', $settingKey), $hostname); if ($database !== null) { config(sprintf('%s.database', $settingKey), $database); } if ($username !== null) { config(sprintf('%s.username', $settingKey), $username); } if ($password !== null) { config(sprintf('%s.password', $settingKey), $password); } } Services/ConnectionService.php
  • 22. Call model from the tenant db - Primary connection - Call model as normally i.e. - Model::find(1);
  • 23. Call model from shared or master db - Switch connection of a model or set the default connection on the model - Retrieve the model using eloquent
  • 24. Call model from shared or master db class Permission extends Model { public function getConnectionName() { return 'shared_database'; } protected $fillable = [ 'name', 'description', 'policy' ]; } Models/Permission.php
  • 25. Inter database relations - A Role has many Permissions - Permissions are stored in shared db - Laravel limitations and how to fix them - Direction of relations SELECT * FROM tenant_database.users AS u JOIN tenant_database.users_roles AS ur ON u.id = ur.user_id JOIN shared_database.roles AS r ON ur.role_id = r.id WHERE u.id = 1;
  • 26. Call model from shared or master db class Permission extends Model { ... private function getTableNameForConnection($table, $connection = null) { return vsprintf('%s.%s', [$this->getDatabaseNameForConnection($connection), $table]); } public function roles() { return $this->belongsToMany( AppModelsRole::class, $this->getTableNameForConnection('role_permissions', 'tenant_database'), 'permission_id', 'role_id' ); } ... } Models/Permission.php
  • 27. Fire an event - Only a problem on Async listeners - Needs a tenant to run
  • 28. Fire an event abstract class TenantEvent extends Event { public function __construct() { if (($tenant = $this->getTenantService()->getTenant()) instanceof Tenant) { $this->setTenant($tenant); } else { throw new MissingTenantException(); } } public function __sleep() { // Unset tenant model for serialization $this->tenant = null; // Continue with sleep return parent::__sleep(); } public function __wakeup() { // Fetch the tenant by id $this->tenant = $this->getTenantService()->find($this->tenantId); $this->tenantId = $this->tenant->id; // Initialize tenant database connection $this->getTenantManager()->connect($this->tenant); // Continue with wake up parent::__wakeup(); } } Abstracts/TenantEvent.php
  • 29. Warnings Everything outside the request lifecycle requires manual tenant switching Cache Broadcast Storage Queues Inter database relations and connections to be used Cross connection transactions
  • 30. Pro’s & Con’s Backups per tenant Easy recovery GDPR Scalability Manageability (migrating to new db environment) Overhead Complexer logic for built in laravel functions: - Commands - Events - Queues - Broadcasting Planning ahead
  • 31. Server layout Layer 4 load balancing
  • 32. Packages I don’t want to do this all by myself: https://github.com/hyn/multi-tenant ★1143 https://github.com/orchestral/tenanti ★406 https://github.com/HipsterJazzbo/Landlord ★525
  • 33. Andere onderwerpen ● Laravel API's and their limitations ● Strangling Laravel with react ● Deploying Laravel to production (With CI) ● Error handling in Laravel with channels and sentry ● Oauth2 implementation with passport (and what its missing) ● Laravel and Kubernetes ● Local development with Docker ● Broadcasting to the world ● Storage in the cloud, and efficient image retrieval (Thumbor and S3) ● Unit testing, Integration testing, Browser testing ● Package development and contributing to open source ● Modular laravel; simulate microservices https://sli.do #F294

Editor's Notes

  • #4: Saas is an application that serves multiple people with teh
  • #9: Scopes for single database
  • #10: Scopes for single database
  • #12: Scopes for single database