Better Auth + Multi-Tenant (Separate DBs per tenant)
Hey everyone,
Seeking advice on integrating Better Auth in a multi-tenant app where each tenant has its own Postgres DB. My current idea involves using Better Auth's
hooks.before
to dynamically create a prismaAdapter
with the tenant-specific PrismaClient by modifying ctx.context.adapter
.
Is this a sound approach, or are there better/recommended ways to pass a dynamic Prisma instance to Better Auth per request? Also, any potential pitfalls or edge cases I should be aware of with this method?
Open to all suggestions!5 Replies
Any reason why you can't have 1 db for better auth, and leave all other dbs for your tennets to use?
Because for our use case, users are strictly scoped to a single tenant and there is no concept of 'global' user that can access multiple tenant
I'm doing something very similar. I got it to where I can get a dynamic auth instance working per request. but the problem is that all underlying code in betterauth isn't tenant aware, for ex, finding a user simply does "WHERE email=$email", wheras I'd need to also append "and tenant=$tenant".
You may not have this issue tho, depending on how you're doing multitenancy, but you can totally get a per-request db client added to a per-request better-auth instance. I then attach this instance to req.auth and use it downstream as a hander
In our app, we have the same db-per-tenant approach. We don't use BetterAuth yet though 🙂 But I assume you should think in terms of providing constant "db adapter" to betterauth, and that adapter must be your own, which would have a pool of connections for each db (that's many connection to every db), which would route the queries to relevant db connection internally depending on its own conditions. We have that in the app now, just not with betterauth yet 🙂
I'm not actually using separate databases. All my users are in one database, one schema, one
users
table, separate only by a tenant_id
column.
I have individual db
connections that I attach per request, but this is just a connection management/cleanup thing.
if my tenant separate could be done at the db connection string, then it'd be no issue, but it's done at the db query, which is a problem I think.
My only option might be to do something hacky like:
- create my own db adapter, that still implements things like user.findUserByEmail(email), as that's what some plugins expect for example
- but use async context to set a tenant-id at a higher level, and read it in the functions implementation.. ughhh