Multitenancy and Meteor


It doesn’t have to be pure node. However, it seems complex enough to exist as it’s own subsystem in the architecture. In my app, Tenant #1 and Tenant #2 might be both using SAML, but doing so through via different SAML SP’s. Plus if I wanted to offer any of my tenant’s additional services (separate meteor apps) in the future, I wouldn’t want the functionality tethered to the first app. So far, I’ve been looking at npm OAuth Providers, and I’m not too impressed with what I’ve found so far… :confused:


Unless you have a good reason to make it a separate thing I’d stick within Meteor. It sounds like something you should break into a package, so it can be used by other apps you write, or published to Atmosphere for others to use. Meteor already has plenty of oAuth support. Check out the accounts-facebook|twitter|google code for examples. I’m not sure why SAML would be much different, but maybe it does need to be totally stand alone.


I’m thinking about using for my authentication, I believe they also handle SAML and CAS and more, so might be really useful for you.


Hi guys,

I am new to meteor and would be really thankful about how you guys are doing with your saas implementation?

The last framework I used (django) had a very elegant multitenant-solution
using subdomains and postgres schemas. So basically while programming your database-access you did not even have to think about tenants. The module would take care of this for you.

Did you guys have to go thru a lot of trouble implementing your secure saas environment?
What do you consider best practise?

I’d be happy to hear your feedback.


Hey guys, I’ve mostly got my multi-tenant app done.

We’re trying to integrate meteorhacks:cluster. We sometimes get 404 errors for POST requests.

Has anyone else successfully configured a multi-tenant app with meteorhacks:cluster so it can scale?


I’ve also run into another roadblock with multitenancy: server side rendering.

In publication functions, (which is normally set to in local development) is localhost:3000 in a server context.


Appears the semi-official best practise with Mongo is to use a separate database (same server) for each tenant.

-Easy deployment for new tenants…
-Easy security with different encryption key for each tenant.
-Easy to extract a tenant’s data when they don’t pay their bill.

Worth watching if you are interested in SAAS with Mongo.

Using Multiple Domains With One App

This will put into perspective the trade-offs among different tenanting solutions

Best way to architect a multi-tenant SaaS?

Hi @babrahams and others…

How are you managing direct calls to the url and routing ?

Say you have a request to

This will load the tenantId, and populate the session.

If on the other hand the user makes a direct call to the url through - i.e. browser URL bar (as opposed to through the app) - then session variable isn’t always in context and doesn’t have the tenantId data at all.

Trying to get this to work with FlowRouter. Namely,

foo's route doesn’t have the session data, when called directly; but if navigated through the app it does.

Subdomain and routing with Meteor is proving interesting :unamused:

Thank you.


Yeah, that’s where it gets a bit tricky. I just live with a lot of round-trips to the server and a lot of loading spinners when someone hits a route directly from the browser URL bar.

Once the app’s client side state is all loaded up via a hideous web of reactivity (where results from the server trigger another round-trip, the results of which trigger another round-trip, etc.), then navigating to new routes within the app is nice and snappy (as the client app state is all in place). But that first start up time is a bit grim …


Glad you’ve confirmed my madness wasn’t alone @babrahams :smile:

There has to be a more elegant solution for this …

As at the moment; it’s the same call from .startup on the client, and them am re-using it in the FlowRouter’s trigger to make sure. Not very pretty :frowning:


Yeah, it’s not an elegant solution, but it’s easy and it works. I’m currently happy enough with the time from initial html/js bundle load to round trips finished / page fully rendered. That said, if anyone comes up with something slicker, I’m all ears. :slight_smile:


I thought I’d post in this thread as it’s been useful so far to me in developing my multi-tenant strategy.

I looked at DB-per-tenant but it seems to complex and expensive right now. So I’ve been taking the approach which is quite similar to @babrahams I believe but simpler. I store the tenantId in the user doc but never let it onto the client. All of my publish functions look like this:

Meteor.publish("data", function() {
    var tenantId = Meteor.users.findOne({_id: this.userId}).tenantId;
    return MyCollection.find({tenantId: tenantId}, {fields: {tenantId: 0}});

I might need to start deducing the tenant from subdomain though. My issue is that if each tenant can have multiple clients invited into the system, how do I allow a user to be added by two different tenants? So for tenant A is different to for tenant B.

My current thinking is that if I prepend the tenantId to their email and store that in meteor.users as their username that will solve the issue. Then when logging in on a tenants subdomain I believe I would just need to use the setCustomSignupOptions in Account UI to generate their username from their email and tenantId.

Any feedback is most welcome!!


It’s a bit late but that’s exactly what does. You define tenants (realms) on which you can enable almost any existing authentication protocol. Your application just talks oAuth2 with keycloak (JWT also supported).


This is a great approach. I currently pass the tenant ID from the subscription on the client, but will have to take a look at this approach of just grabbing it on the server instead.

I have two tenant-related items stored on the user object:

currentOrg is a string representing the organization that the user is currently logged into. This is used as a variable for all publications.

tenants is an array (actually, really should be an object) of all the organizations a user has access to.

Then I use the Roles package to manage permissions within each tenant by matching the Roles group to the tenant ID.

When I create a new user, I first check if the email address already exists, and if so just append the tenants credentials to their user profile and send a separate welcome email.

I know there’s ways to make it better, but that seems to be working for now. Like you, I’d like to better understand how to setup Nginx to use subdomains.

Hope that helps!


The approach I use is very similar to that of @allenfuller.

Note: you can get away without using nginx at all to manage subdomains. Just make sure your DNS has a wildcard subdomain record like:

*       IN      A

Then do this on the client. (That’s a link to post earlier in this thread detailing how I get the tenant from the subdomain using client side code and a method call.)

I admit, this is not a particularly elegant approach, and requires more round trips than anyone would like, but it does work.


Interesting approach Allen. So are you saying you’re doing this?

  • Client signs up for tenant A - receives regular Enrolment mail.
  • Client signs up for tenant B - receives a “you now have access to tenant B with your MyProduct login/password” mail.

And then when logging in it checks the subdomain to then see which tenant is the currentOrg for the user?


Yep! And then I added a small switchOrg feature to the user’s menu so they can move back and forth:

<template name="navMain">
  <ul class="nav navbar-nav nav-main hidden-sm hidden-md hidden-lg">
   [ ... ]
  <ul class="nav navbar-nav navbar-right nav-desktop hidden-xs">
    <li role="presentation" class="dropdown">
      <a href="#" class="dropdown-toggle" data-toggle="dropdown">{{currentUser.emails.[0].address}} <span class="caret"></span></a>
      <ul class="dropdown-menu" role="menu">
        <li><a href="{{pathFor 'user'}}">My Profile {{roles}}</a></li>
      {{#if multiOrgs}}
          <a href="#" data-toggle="modal" data-target="#switchAccounts">Switch Accounts</a>
          <span class="navbar-text">(Currently in {{currentOrg}})</span>
        <li class="logout"><a href="#">Logout</a></li>

And the helper:

  currentOrg: () => {
    return Meteor.user().profile.currentOrg;
  // Checks if the user is a user for more than one organization, or a global admin
  multiOrgs: () => {
    let userId   = Meteor.userId(),
        orgs     = Meteor.users.findOne({_id: userId}, {fields: {organizations: 1}}),
        admin    = Roles.userIsInRole(userId, 'admin', Roles.GLOBAL_GROUP),
        orgCount = orgs.length;
    if (orgCount > 1 || admin) {
      return true;
    } else {
      return false;

I hesitate to share code as I’m still pretty new to this myself. In fact, I think my whole approach started with what I read from @babrahams on this thread!


Cool. I have been thinking of the tenant separation as a very hard security line and doing everything to make sure someone from one tenant can never see another but your approach offers a lot more flexibility and has got me thinking. I’ll post back here again after I have a chance to try it out.


How would this work on a mobile application if the domain is localhost?