yordisprieto

yordisprieto

How to approach a multitenant architecture solution?

I am currently asking myself what would be the best solution when it comes to a SaaS and the implementation of the multitenant part of it.

Either use infrastructure or do it at the code level.

For example,

I am currently working on some Identity and Access Management system and I get stuck in the dilemma of which solution to go for.

  1. Use the network infrastructure.
  2. Use database multitenant

What I mean with this is that I would normally spawn multiple servers and probably use some API gateway or subdomains or whatever that redirect the API calls to the correct server based on the business.

What I like about this is that I could maintain my code written as it was a singular business so details of which tenant I referring to goes away.

For example

We need to get some code or whatever to find the tenant.

tenant = find_the_tenant_somehow()

Accounts.create_account(tenant, user_params)

vs

We don’t need to pay attention to that because the server is running this code is for a single business.

Accounts.create_account(user_params)

This first example needs somehow a way to identify which business/tenant you are referring to, the second is you don’t need to pay attention to that.

I am not sure what would be the benefit of using multitenant and drive this logic at the code level since I never done this before.

Is there a better way?

I really would like to know your opinions about it and what do you recommend if you would use one of those packages as a dependency as well.

I guess in modern stacks is easier to spawn servers so we do not need to keep doing the old way to do things unless we definitely want the data to be shared but for these use cases is really rare so I am not concern about that.

Please leave your feedback.

Most Liked

aseigo

aseigo

Perhaps start with a simple test project and see how it works in practice, and then you will have some data to base a decision off of.

With ecto and triplex, it’s an extra line per tenantized query and you can pick out the tenant id in a plug so that is done in exactly one place. Not a big deal, really.

Here’s a screencast you may be interested in:

notriddle

notriddle

I’ve done both approaches for multitenant applications, because the situation differed in subtle ways:

  • How many tenants do you expect? If it’s only a couple of dozen, and each one pays you plenty of monies, then you should probably just do a manual onboarding process and have each tenant on their own separate instance of your app. It allows you to give each tenant their own update schedule, means you never need to worry about them stomping all over each other, and can just generally babysit each customer as much as they deserve. On the other hand, if you expect thousands of tennants that don’t pay you very much, then you should do as much colocating as possible.

  • How much overlap do you expect them to have? If it makes business sense to give all your users a single account throughout your system, then you definitely don’t want to mess with SSO solutions right out the gate. That’ll cancel out the “simplicity” you would’ve otherwise had.

  • Do you expect your users to do local installations of your app? Worse, do you expect them to locally install the app and then have the app turn around and phone the mothership? If so, you might as well have all the hosted tenants on separate infrastructure behind an API gateway, so that the “cloud service” and the “on-prem service” can be kept as similar as possible.

By the way, if you get the choice wrong, you can fix it later. Slack started with all the tenants on separate VMs, but merged them into a single database later. Aspects of their UX still kind of reflect the old way, but it works and they’re doing fine overall despite the pivot.


You might notice that most of these aren’t really technical considerations, they’re business decisions. You need to decide if you want lots of cheap users, a self-serve web app, and not much integration, or if you want to go the Enterprise-with-a-capital-E path where your tenants each work with a sales representative (if this is a new company, that “sales rep” will probably be the same person as the CEO) and might get custom modules because one tenant asked for it.

aseigo

aseigo

Spinning up multiple instances works alright if you have a limited number of tenants, but becomes increasingly wasteful as the number of tenants rises. Upgrades become increasingly more onerous as instead of upgrading the number of systems required to satisfy actual use and demand, you need to update one instance per tenant. It also means that every new tenant requires an update to the front-end proxies, and whenever a new tenant is added that either the sign-up/creation machinery needs to be able to influence the orchestration infrastructure (one more attack surface), or it requires manual intervention. (That last point is less important if tenants come on with a manual process on your part anyways.) Infrastructure management tools are pretty amazing these days, but there is no reason to be more wasteful or make life more complicated than necessary.

Another downside with multiple instances is that you now have 3 places to track your tenancy settings: the front-end proxies, the configuration on each deployment, and in your code. One may expect that putting the tenancy into config means removing all such considerations from you code … but should there be shared resources (e.g. common database tables / information) between tenants, then you end up having one path for tenant-specific resources and general resources. shrug

Multi-tenancy is not perfect, of course, but it is simpler to manage deployments for and allows easier sharing of common resources. It also does mean that per-tenant features can not be controlled by application-global configuration, but needs to be per-tenant … on the other hand that means all your tenant information is kept in one place (usually the database).

Tools like triplex makes tenancy easy, as well.

brightball

brightball

For what it’s worth, the approach of setting a tenant_id on each table keeps things simple and scales well. From there, if you actually grow the database farther than a single instance you will be ready for Citus.

Where Next?

Popular in Questions Top

shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
quazar
How to set Jason to encode all fields in ecto schema, I don’t care about security and implementing only is taking long list of attributes...
New
sacepums
Hey guys. I'm new to elixir and im really stocked about it. But I ran into a bit of problem - I need to convert a date sting, for examp...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New

Other popular topics Top

sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 49522 488
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 35421 110
New
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 42633 214
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New

We're in Beta

About us Mission Statement