# ActiveMultiTenant

**URL:** <https://discuss.rubyonrails.org/t/activemultitenant/74774>\
**Category:** A May Of WTFs\
**Tags:** activerecord\
**Created:** [May 11, 2020, 12:22am UTC](https://discuss.rubyonrails.org/t/activemultitenant/74774 "2020-05-11T00:22:20Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![jduff](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/jduff/32/1442_2.png) [@jduff](https://discuss.rubyonrails.org/u/jduff)\
**Post date:** [May 11, 2020, 12:22am UTC](https://discuss.rubyonrails.org/t/activemultitenant/74774/1 "2020-05-11T00:22:20Z")

</div>

Multi tenant applications are very common, having something out of the box to handle this would be really nice. Even if a full solution isn’t possible, every application is different, but maybe some tools to make it easier / help you do the right thing?

ex I usually add a validation that checks associations are also associated with the same tenant when created.

---

<div class="post-metadata">

**Author:** ![yoelblum](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/yoelblum/32/3284_2.png) [@yoelblum](https://discuss.rubyonrails.org/u/yoelblum)\
**Post date:** [May 11, 2020, 8:57pm UTC](https://discuss.rubyonrails.org/t/activemultitenant/74774/2 "2020-05-11T20:57:56Z")

</div>

I wonder if there’s a better way to check how prevalent a thing is in our ecosystem. So far it feels to me like we’re all going by our gut feeling (I’m guilty of this as well by asking for a baked in admin framework for Rails). As for multi tenancy, this is what I can find [Category: Multitenancy - The Ruby Toolbox](https://www.ruby-toolbox.com/categories/Multitenancy) . What do we make of the numbers, can we estimate if this means a majority of apps is using this?

---

<div class="post-metadata">

**Author:** ![djch](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/djch/32/1352_2.png) [@djch](https://discuss.rubyonrails.org/u/djch)\
**Post date:** [May 11, 2020, 11:27pm UTC](https://discuss.rubyonrails.org/t/activemultitenant/74774/3 "2020-05-11T23:27:01Z")

</div>

I’m not sure if it counts as “true” multi-tenancy but I think the accounts system in Basecamp is quite brilliant and would be broadly applicable to most B2B rails apps. I think it’s basically a rack middleware that’s scoping all routes to an account ID, which goes into current.rb etc. I’m a very inexperienced rails programmer, but this is one of those things I’d love to be baked in (as well some more tools for user authentication).

---

<div class="post-metadata">

**Author:** ![samsaffron](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/samsaffron/32/596_2.png) [@samsaffron](https://discuss.rubyonrails.org/u/samsaffron)\
**Post date:** [May 15, 2020, 5:49am UTC](https://discuss.rubyonrails.org/t/activemultitenant/74774/4 "2020-05-15T05:49:49Z")

</div>

I know @eileencodes has some plans to get multi tenancy into Rails.

I agree that the current state of affairs is not perfectly ideal. The good news is that the internals of Rails and ActiveRecord are very multi tenant friendly. We have been using it for many many years at Discourse. The bad news is that you need a gem/special library.

At Discourse we use:

> **[GitHub - discourse/rails\_multisite: Multi tenancy for Rails applications](https://github.com/discourse/rails_multisite)**
>
> Multi tenancy for Rails applications. Contribute to discourse/rails\_multisite development by creating an account on GitHub.

We run 100-300 customers on a single cluster, each customer has a dedicated database, all 100-300 databases are clones structure wise (so we can reuse schema cache) but have distinct data.

The one big pitfall we had to work through is keeping on top of all the connections, this involves both running pgbouncer and a custom connection reaper cause unfortunately atm every connection pool gets a dedicated thread to reap connections [discourse/discourse.rb at 4601833e4ed98aaaaf90c0ddab2bfebfae42db7c · discourse/discourse · GitHub](https://github.com/discourse/discourse/blob/4601833e4ed98aaaaf90c0ddab2bfebfae42db7c/lib/discourse.rb#L746-L761)

We have to be really careful and measured moving towards a native multi tenancy story cause there are many dragons, some of which are not even under rails control. (PG performance suffers with 1000s of open connections for example)

---

<div class="post-metadata">

**Author:** ![jduff](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/jduff/32/1442_2.png) [@jduff](https://discuss.rubyonrails.org/u/jduff)\
**Post date:** [May 15, 2020, 12:04pm UTC](https://discuss.rubyonrails.org/t/activemultitenant/74774/5 "2020-05-15T12:04:27Z")

</div>

Thanks for the link, I hadn’t come across `rails_multisite` before.

I think one of the challenges with something like this is there at a lot of different ways to implement it, all with different tradeoffs and pitfalls to avoid. We have the database per tenant approach you mentioned, you can use a schema per tenant (with Postgres at least) [GitHub - influitive/apartment: Database multi-tenancy for Rack (and Rails) applications](https://github.com/influitive/apartment), at Shopify we put the account id on every table and scoped the queries automatically.

That being said I’m pretty sure there are useful building blocks from all of these and having them supported natively within rails would help developers make safer and better supported choices.

It also sounds like some work is already happening in this direction if @eileencodes is extracting some of their approach from Github which is awesome. I’m sure Shopify will be contributing something back for composite primary keys which will be another great building block [https://twitter.com/jeremycole/status/1260305100863451136?s=21](https://twitter.com/jeremycole/status/1260305100863451136?s=21)

---

<div class="post-metadata">

**Author:** ![eileencodes](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/eileencodes/32/927_2.png) [@eileencodes](https://discuss.rubyonrails.org/u/eileencodes)\
**Post date:** [May 15, 2020, 5:06pm UTC](https://discuss.rubyonrails.org/t/activemultitenant/74774/6 "2020-05-15T17:06:58Z")

</div>

Sharding support was implemented in [Add support to `connected_to` and `connects_to` for horizontal sharding by seejohnrun · Pull Request #38531 · rails/rails · GitHub](https://github.com/rails/rails/pull/38531). We’ll be implementing auto-routing for shards in Rails 6.2. We’ll also be upstreaming the ability to support associations across shards/clusters by creating 2 queries instead of joining.

---

<div class="post-metadata">

**Author:** ![Betsy\_Haibel](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/betsy_haibel/32/1092_2.png) [@Betsy\_Haibel](https://discuss.rubyonrails.org/u/Betsy_Haibel)\
**Post date:** [May 15, 2020, 5:34pm UTC](https://discuss.rubyonrails.org/t/activemultitenant/74774/7 "2020-05-15T17:34:03Z")

</div>

Abstracting out the process for associating across clusters will be life-changing for my current project. So excited. 😃

---

<div class="post-metadata">

**Author:** ![eileencodes](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/eileencodes/32/927_2.png) [@eileencodes](https://discuss.rubyonrails.org/u/eileencodes)\
**Post date:** [May 15, 2020, 6:28pm UTC](https://discuss.rubyonrails.org/t/activemultitenant/74774/8 "2020-05-15T18:28:14Z")

</div>

The work for associating across clusters is already done in a private gem at GitHub, we just need to extract it into Rails once we’re confident it covers most use cases. Should be released in 6.2 😄

---

<div class="post-metadata">

**Author:** ![Eric\_Hayes](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/eric_hayes/32/1329_2.png) [@Eric\_Hayes](https://discuss.rubyonrails.org/u/Eric_Hayes)\
**Post date:** [May 15, 2020, 6:44pm UTC](https://discuss.rubyonrails.org/t/activemultitenant/74774/9 "2020-05-15T18:44:18Z")

</div>

@eileencodes thanks for all your work on this stuff! It’s so cool that we smaller shops can benefit from the path that Github and others have trod.

---

<div class="post-metadata">

**Author:** ![ferngus](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/ferngus/32/5127_2.png) [@ferngus](https://discuss.rubyonrails.org/u/ferngus)\
**Post date:** [May 26, 2020, 5:51pm UTC](https://discuss.rubyonrails.org/t/activemultitenant/74774/10 "2020-05-26T17:51:16Z")

</div>

> [@djch](#):
>
> I’m not sure if it counts as “true” multi-tenancy but I think the accounts system in Basecamp is quite brilliant and would be broadly applicable to most B2B rails apps. I think it’s basically a rack middleware that’s scoping all routes to an account ID, which goes into current.rb etc. I’m a very inexperienced rails programmer, but this is one of those things I’d love to be baked in (as well some more tools for user authentication).

Think this is the one you’re referring to?

> <https://gist.github.com/dhh/23dea207f4e95d4b3ec5fac969c4a833>

---

<div class="post-metadata">

**Author:** ![santib](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/santib/32/10037_2.png) [@santib](https://discuss.rubyonrails.org/u/santib)\
**Post date:** [May 26, 2020, 7:49pm UTC](https://discuss.rubyonrails.org/t/activemultitenant/74774/11 "2020-05-26T19:49:18Z")

</div>

> [@jduff](#):
>
> you can use a schema per tenant (with Postgres at least)

Unfortunately this solution that (at least to me) looked really promising at the beginning turned out to be quite dangerous at least on Heroku [Heroku Postgres | Heroku Dev Center](https://devcenter.heroku.com/articles/heroku-postgresql#multiple-schemas)

My take is that either the `tenant_id` in every table + default\_scope or the multiple DBs are the way to go for multi tenancy depending on the project situation.

---

<div class="post-metadata">

**Author:** ![djch](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/djch/32/1352_2.png) [@djch](https://discuss.rubyonrails.org/u/djch)\
**Post date:** [May 26, 2020, 11:26pm UTC](https://discuss.rubyonrails.org/t/activemultitenant/74774/12 "2020-05-26T23:26:56Z")

</div>

Yes! It was cool to see DHH post that after my comment here. I hope somebody does flesh that out into a PR or gem or something.

---

<div class="post-metadata">

**Author:** ![ferngus](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/ferngus/32/5127_2.png) [@ferngus](https://discuss.rubyonrails.org/u/ferngus)\
**Post date:** [May 27, 2020, 2:13am UTC](https://discuss.rubyonrails.org/t/activemultitenant/74774/13 "2020-05-27T02:13:28Z")

</div>

> [@santib](#):
>
> Unfortunately this solution that (at least to me) looked really promising at the beginning turned out to be quite dangerous at least on Heroku

I’m running this on Heroku. No issues yet with 20+ tenants. Then again my use case probably isn’t going to grow dramatically just yet.

---

<div class="post-metadata">

**Author:** ![yshmarov](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/yshmarov/32/2475_2.png) [@yshmarov](https://discuss.rubyonrails.org/u/yshmarov)\
**Post date:** [October 4, 2020, 9:03am UTC](https://discuss.rubyonrails.org/t/activemultitenant/74774/14 "2020-10-04T09:03:37Z")

</div>

Multitenancy is indeed a big feature, however there is no single-right way to implement it.

If you want schema-based multitenancy, Rails 6 already supports easy schema-switching.

If you want row-based multitenancy, there are more than enough good gems.

---

<div class="post-metadata">

**Author:** ![hoppergee](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/hoppergee/32/1318_2.png) [@hoppergee](https://discuss.rubyonrails.org/u/hoppergee)\
**Post date:** [October 4, 2021, 5:44pm UTC](https://discuss.rubyonrails.org/t/activemultitenant/74774/15 "2021-10-04T17:44:26Z")

</div>

I just released a new gem: [multi-tenant-support](https://github.com/hoppergee/multi-tenant-support) which mainly focus on protecting data leak on ActiveRecord level for multi-tenant.
