Multi-tenant architecture using schema.
See original GitHub issueIssue type:
[X] question [ ] bug report [ ] feature request [ ] documentation issue
Database system/driver:
[ ] cordova
[ ] mongodb
[ ] mssql
[ ] mysql
/ mariadb
[ ] oracle
[X] postgres
[ ] cockroachdb
[ ] sqlite
[ ] sqljs
[ ] react-native
[ ] expo
TypeORM version:
[X] latest
[ ] @next
[ ] 0.x.x
(or put your version here)
Steps to reproduce or a small repository showing the problem:
We are using TypeORM trough NestJS framework, currently trying to resolve issue with multi-tenancy. Currently what we see for PostgreSQL there are 3 different options to handle multi-tenant architecture in Single server/cluster mode.
- Single server/cluster, single database, tenant column in each table.
- Single server/cluster, single database, multi schema per customer.
- Single server/cluster, multi database per customer.
While the 1st one could work the best, first of all for some security reasons we cannot go with it, especially when data grow over time the query performance will drop down, the 3rd one would require opening new connection for each of the database, as Google Cloud SQL (ref. https://cloud.google.com/sql/docs/quotas) has limits with max concurrent connections at time, this one could make some issues also.
We decided that we will go with option 2, so for each customer we have scripts which copy all tables from template schema into newly created schema.
E.g. customer1, customer2, customer3, customer4, customer5… so all tables and entities looks exactly the same as in the others (during schema change we are using migration tool/custom script to update schema in each customer schema).
Currently as far as we get there is no multi-tenant supported in TypeORM within Schemas (there is an option but it is using QueryBuilder on top, but we want to use all functionality of TypeORM which saves us a lot of time with development ref. https://stackoverflow.com/questions/57459643/typeorm-dynamically-set-database-schema-for-entitymanager-or-repositories-at-ru) in some sort of dynamic way, there are however Entities which we can mark as specific schema, but having this for 100+ customers in one database would be overkill to add new classes per every customer that is coming to our software (ref. https://github.com/typeorm/typeorm/issues/1019).
What would be the best option to go trough TypeORM in dynamic schema?
E.g.
import { Injectable, Inject } from '@nestjs/common';
import { Repository } from 'typeorm';
import { Photo } from './photo.entity';
@Injectable()
export class PhotoService {
constructor(
@Inject('PHOTO_REPOSITORY')
private readonly photoRepository: Repository<Photo>,
) {}
async findAll(): Promise<Photo[]> {
return await this.photoRepository.useSchema('customer1').find();
}
}
While the .useSchema could basically do query schema based like this:
SELECT * FROM customer1.photoRepository LIMIT 1;
I see there might be one workaround to basically create copy of tables with different prefix, but while PostgreSQL has schema supported i don’t think this is an option. Having multiple connections in configuration using createConnections isn’t option also, as the customer’s instances can be created on fly.
There is also another option but it is on the database level to set search schema per user on the database level, but we want to avoid any miss-configuration there (it also require to create multiple connections at the init of an app while it has to be dynamic, this is not an option too).
ALTER USER customer1 SET search_path = customer1;
Kind request to provide some help or examples in this area.
Issue Analytics
- State:
- Created 4 years ago
- Reactions:43
- Comments:17 (3 by maintainers)
@KleinMaximus This is dependent on your backend and architecture and how you handle it.
I make it working with NestJS middleware which manages the connections. Before each request I am validating if connection is opened in “Connections Manager” if not, opens it.