Lessons Learned From Making FlowWright Multi-Tenant SaaS Software

Learn from the lessons learned

Last published at: April 18th, 2024

We’ve been on the research path of making FlowWright multi-tenant Saas for a while now.  We have spent months, and years in research on what’s the best solution to build for FlowWright.  We learned a lot, and here’s what we learned:


  • Many others have gone down this path before us, learn from them, mostly learn from their lessons and mistakes
  • Spend 90% figuring out, and 10% building. Try to reuse what you already have as much as possible. From an architectural view, many approaches can be taken when making an application multi-tenant or Saas.  We started going down one path but realized that we would have to build a lot more even though the design was very good.  However given certain constraints, we were able to change our design and approach to make use most of what we already have.  So we changed and used 90% of what we have, and only built 10%.
  • Figure out what functionality you want to separate between a tenant manager and a tenant. In certain functionality, you will be forced to do this, especially in operations where it affects other tenants.  For example, FlowWright provides functionality to define and use Microservices.  Microservices need to be compiled so they can act as true web APIs hosted by the application.  In .net environments, when a DLL is compiled and placed within the BIN directory, the whole application domain needs to be reloaded.  This can cause a disturbance to all tenants of the application, while the application domain needs to be reloaded, no user can access the application.  Given this situation, functionality such as this is moved to the tenant manager, where it can be managed and performed by an application administrator at a time of less application use.  This is similar to how database servers operate, even though they support many # of databases, upgrades to database servers and databases are performed at certain periods to minimize disruptions to applications that use these databases.
  • It’s very true, that caching is very important, especially in multi-tenant environments, given the # of calls over the wire to the database. Use caching where it makes sense, and early on, this will reduce the # of calls going to the database significantly and also increase the performance of your application.  Be careful, don’t cache items for too long, they become stale and can produce wrong results, have different cache expirations based on the item.  In our case, we built a smart cache, depending on the tier accessing the caching layer, caching is smart enough to use the appropriate cache.  For example, if the user interface or the API is accessing the caching layer, then the application caching is used.  If the workflow engine is running and caching is accessed by engine child processes or API calls, then a more high-performance cache is being used.  A high-performance cache is hosted within the workflow engine service using a lightweight web server.
  • Engines also needed quite a bit of change, since engines now act against multiple tenants, they need to properly manage resources. Given that new tenants can come on board dynamically at any time, engines also need to refresh their configuration from time to time.  Now all FlowWright engines are smart enough to auto-refresh their configuration information, there are challenges here, but can be done using the proper architecture.  Especially when engines are processing, it is not easy to change their configuration information,  but can be done using proper locking mechanisms on objects and by using objects that support concurrency.
  • From a storage perspective, file and data, storage and access have to be tenant-based.
  • Multi-tenant architecture also plays well with polymorphism concepts in object-oriented programming, so when developing your object's inheritance is important. Even though all are treated as tenants, the master tenant is a bit different from a tenant since it holds the configuration information for the rest of the tenants.  From a design perspective, the master tenant will inherit from the tenant, so that methods defined within the tenant can be inherited by the master tenant and tenant objects can act to any method through polymorphism, without having specific logic to determine the type of object.
  • Another design that we have seen is for all the tenants to share configuration through the master tenant. This design has pros and cons. Pros are that the configuration is only maintained within one database and shared across tenants, the cons are there are way too many calls going into the master tenant to retrieve configuration information by all tenants.  Some of the other cons are, a single point of failure if the master tenant goes down, and all other tenants are down too.  With the design of each tenant having its configuration information, it makes it easier to troubleshoot issues or to move the tenant.

Above are the lessons we learned from making FlowWright into a multi-tenant/SaaS application. Each of our experiences is different, hope you can learn some lessons and apply them to your software project.