La multitenancy, c’est l’un de ces sujets qu’on découvre généralement trop tard. On démarre une application B2B en SaaS, on la lance, elle décolle, et un jour on se rend compte qu’on a accumulé les données de 200 clients dans la même table objet_confidentiel_du_tenant avec une colonne client_id qu’il ne faut surtout, surtout pas oublier dans le WHERE.
À ce stade, il est encore possible de bien faire les choses, mais le coût n’a plus rien à voir avec celui d’une décision prise au démarrage.
Cette série revient sur le sujet avec un parti pris : la multitenancy n’est pas un pattern qu’on plaque sur une appli existante, c’est un choix d’architecture qui se prend très tôt, et qui se décline ensuite à plusieurs niveaux (base de données, cache, fichiers, queues). On va parcourir ces niveaux un par un, dans le contexte d’une application Laravel concrète.
Ce premier article pose le décor : qu’est-ce qu’un tenant, qu’est-ce qu’on cherche à isoler, et surtout, est-ce que vous devriez vous lancer là-dedans, ou alors, est-ce une problématique qui ne vous concerne pas ?
Ces articles sont la mise au propre de la conférence que j’ai donnée lors du Forum PHP 2025. Vous pouvez retrouver la vidéo sur la chaîne YouTube de l’AFUP, l’association qui fait vivre la communauté PHP francophone (afup.org).
La définition courte
La multitenancy est une architecture logicielle où une seule instance d’application sert plusieurs clients de manière isolée. Ces clients sont appelés tenants, au sens où ils sont locataires de l’infrastructure dont vous êtes le propriétaire. L’application est mutualisée, mais les données de chaque tenant restent étanches : un tenant ne voit jamais les données d’un autre, et idéalement, il ne peut même pas savoir qu’ils existent.
C’est ce qui distingue un SaaS B2B d’un déploiement on-premise : avec la multitenancy, vous ne livrez pas une copie de votre application à chaque client, vous leur servez la même, en garantissant l’isolation par construction, et pas par déploiement.
Deux objectifs principaux derrière cette approche :
La sécurité par construction. L’étanchéité ne doit pas dépendre du fait qu’un développeur n’ait pas oublié un WHERE tenant_id = ? dans une requête. Si l’isolation repose sur la rigueur humaine, elle finira par céder. L’objectif d’une bonne architecture multi-tenant, c’est qu’il devienne impossible (ou en tout cas très difficile) d’écrire une requête qui fuit des données entre tenants.
La performance et la scalabilité. Pouvoir faire grossir chaque tenant indépendamment, isoler les ressources pour qu’un client énorme ne dégrade pas le service des autres, appliquer des stratégies d’optimisation différentes selon les profils d’usage.
Si l’un de ces deux objectifs ne vous concerne pas, posez-vous franchement la question de savoir si la complexité d’une architecture multi-tenant en vaut la chandelle.
Qu’est-ce qui constitue votre tenant
C’est la première vraie décision, et celle qu’on prend généralement trop vite. Un tenant, c’est l’entité dont vous voulez isoler les données, et, par construction, complexifier le partage de données avec une autre entité.
Quelques candidats classiques :
- L’organisation cliente. C’est le cas le plus courant en B2B. Chaque entreprise qui s’inscrit sur votre application est un tenant. Tout ce qu’elle crée (utilisateurs internes, projets, factures, contenus) lui appartient et ne sort pas de son périmètre.
- L’équipe ou le département. Vous voulez qu’au sein d’une même entreprise, deux équipes ne se voient pas. C’est typique des outils RH ou des plateformes de gestion de projet où le cloisonnement interne fait partie de la promesse.
- L’utilisateur. Plus rare comme tenant primaire, mais ça peut arriver dans certains produits où chaque utilisateur est une île, un outil de notes personnelles, par exemple. Attention : si demain vous voulez permettre du partage et de l’interaction entre utilisateurs, ce choix devient un piège.
En cas de doute, prenez la séparation la plus haute dans la hiérarchie. Démarrer avec un tenant “organisation” et avoir besoin de cloisonner par équipe à l’intérieur, c’est du code à ajouter, pas une refonte. Démarrer avec un tenant “équipe” et vouloir partager des choses entre équipes d’une même entreprise, c’est beaucoup plus douloureux.
Il faut aussi distinguer deux choses qu’on a vite fait de confondre : l’identifiant du tenant et l’identifiant de l’objet métier qu’il représente. Votre tenant peut être lié à une Organization côté métier, mais son identifiant interne (celui qu’on retrouvera dans les noms de schéma, les préfixes de cache, les buckets S3) gagne à être indépendant, typiquement un UUID dédié. Vous y gagnerez plus tard quand il s’agira de renommer une organisation, de fusionner deux clients, ou de gérer un essai gratuit avant rattachement à un compte définitif.
Multitenancy ou pas, décider honnêtement
On va éviter le piège classique des comparatifs en tableau. La vraie question est plus simple : quel est le coût d’une fuite de données entre deux clients ?
S’il est très élevé (B2B, données sensibles, réglementation type RGPD, certifications type ISO 27001), alors vous voulez de l’isolation forte, et la multitenancy en est l’outil principal. S’il est faible ou nul (B2C avec des données publiques, ou contenu non sensible), vous compliquez probablement les choses pour rien.
Les cas où la multitenancy fait clairement sens :
- Application SaaS B2B avec plusieurs entreprises clientes.
- Données sensibles à isoler par client (RH, santé, finances, contrats).
- Besoin de faire grossir une partie de l’infrastructure indépendamment pour certains tenants (un client énorme ne doit pas dégrader les autres).
- Exigences réglementaires sur la localisation ou l’isolation des données.
Les cas où c’est probablement de la sur-ingénierie :
- Vous n’avez qu’un client, et il n’est pas prévu qu’il y en ait d’autres. Inutile.
- Les données sont publiques et partagées entre utilisateurs. Une plateforme de blog grand public n’a aucun intérêt à isoler par tenant.
- Vous êtes en B2C avec très peu de besoin d’isolation. L’utilisateur peut être un tenant logique, mais vous n’avez pas besoin de l’appareillage complet.
Un cas intermédiaire qui mérite un mot : les applications B2B2C, où vous avez des entreprises clientes (tenants) qui ont elles-mêmes leurs propres utilisateurs finaux. Là, la multitenancy est presque toujours indiquée, vos tenants sont les entreprises, et vous gérez les utilisateurs à l’intérieur de chaque tenant.
Pourquoi maintenant, et pas plus tard
Le coût d’une mise en place dépend de manière très marquée du moment où vous vous y mettez.
Au début du projet, quelques heures de mise en place. Vous écrivez vos premières migrations en sachant qu’elles vont vivre dans un schéma par tenant (ou avec une colonne tenant_id, ou dans une base dédiée), et tout le reste s’aligne dessus naturellement.
En début de production, quelques jours à quelques semaines. Vous avez déjà des données, mais peu de tenants, et le code n’est pas encore trop éparpillé. Une migration est nécessaire, mais le périmètre reste maîtrisable et l’opération facile à effectuer.
En production mature, des mois, voire un projet à part entière. Vous avez des centaines (ou des milliers) de clients, du code historique, des intégrations externes qui dépendent de la structure actuelle, des sauvegardes incrémentales qui ne s’adapteront pas toutes seules. À ce stade, ce n’est plus un refactoring : c’est un chantier qui mobilise une équipe complète sur plusieurs trimestres.
Le conseil qu’on peut en tirer est court : si vous pensez avoir un jour besoin de multitenancy, mettez-la dès maintenant. Même une implémentation simple (par exemple une colonne tenant_id et un global scope) vous épargnera énormément de douleur plus tard, et vous laissera la possibilité de migrer vers une stratégie plus stricte (schémas, bases dédiées) le jour où vous en aurez besoin.
Changer de stratégie de silotage à l’intérieur d’une application déjà multi-tenant, c’est un projet réalisable. Passer d’une application non multi-tenant à une application multi-tenant, c’est un autre niveau de difficulté.
Ce qui vient ensuite
Cette série va décliner la multitenancy dans tous les compartiments d’une application Laravel typique. L’angle reste pratique : pas de catalogue théorique des architectures possibles, mais des stratégies concrètes, leur coût opérationnel, et le code qui va avec.
Au programme :
- Cet article : décor, définition, identifier son tenant, décision oui/non
- Stratégies de silotage en base de données : colonne, schéma, base dédiée ; le détail de PostgreSQL (RLS, schemas) ; un mot sur MariaDB et MongoDB
- Cache et fichiers : préfixe, tags, buckets dédiés
- L’implémentation côté Laravel : Spatie vs Stancl, modèle Tenant, détection, bascule entre tenants
- Aller plus loin : commandes, queues, tenant par défaut, migrations à la création, séparer actifs et inactifs
L’objectif n’est pas de cocher toutes les cases possibles. C’est de vous donner suffisamment d’éléments pour faire des choix informés, et de partager les arbitrages qui ont bien vieilli dans des projets réels.