Skip to main content

Multi Tenancy with Codeigniter

In this post I will show you how I converted my normal Codeigniter application into a multi-tenant system.(first step to a SaaS implementation)
Note - This implementation is a separate DB multi-tenancy implementation.

Lets say we have an up and running CI application name ci_app, with the directory structure like this
./application/ many other important directories
which is accessed through browser like http://localhost/ci_app

So to implement the multi-tenant arch we are most concerned about the following files, and we will be editing them
  1. ./index.php
  2. ./application/config/config.php
  3. ./application/config/database.php
And also we need to create a few new ones
  1. Create a tenant folder in your www root directory, lets say tenant_1
  2. Cut the ./index.php from ci_app and paste it in tenant_1 directory 
  3. Create a blank file config.php in tenant_1 directory
  4. Create a uploads directory for file uploads
  5. Create some tenant specific asset directory lets say tenant_1_asset


The config.php file in tenant_1 folder is the main config file containing vital config data like the system, app and asset path, database configurations, and any other config for that matter which are tenant dependent
Here is what we need to put in tenant_1/config.php
/* CORE APP config */
$_SSS['app']['base_dir'] = $_SERVER['DOCUMENT_ROOT'];

$_SSS['app']['tenant_folder'] = 'tenant_1'; //folder name
$_SSS['app']['app_folder'] = 'ci_app'; //folder name
$_SSS['app']['asset_folder'] = 'tenant_1_asset'; //folder name with a trailing slash only if there is an asset folder else leave blank

$_SSS['app']['system_path'] = $_SSS['app']['base_dir'].'/'.$_SSS['app']['app_folder'] .'/system/'; //will be sed by the CI index file
$_SSS['app']['application_path'] = $_SSS['app']['base_dir'].'/'.$_SSS['app']['app_folder'] .'/application/'; //will be used by the CI index file
$_SSS['app']['base_url'] = 'http://'.$_SERVER["SERVER_NAME"].'/'.$_SSS['app']['app_folder'];
$_SSS['app']['tenant_url'] = 'http://'.$_SERVER["SERVER_NAME"].'/'.$_SSS['app']['tenant_folder'];
///The above config variable are defined to create the basic paths and URLs required for the app to work, which are defined just below

/* Main Paths and urls */
if(! defined('APP_TENANTPATH')){
    define('APP_TENANTPATH', $_SSS['app']['base_dir'].'/'.$_SSS['app']['tenant_folder'].'/');//this will be used by ci_app config files to load this config file
    define('APP_TENANTURL', $_SSS['app']['tenant_url']);//this the path that will show on the browser and will be used for accessing the controllers and methods
    define('APP_ASSETURL', $_SSS['app']['base_url'].'/'.$_SSS['app']['asset_folder']);//this will be required to access tenant specific assets}

/* DB config */
$_SSS['app']['db_host'] = 'my_db_host';
$_SSS['app']['db_user'] = 'tenant_1_user';
$_SSS['app']['db_pass'] = 'tenant_1_pass';
$_SSS['app']['db_name'] = 'tenant_1_db';
$_SSS['app']['db_driver'] = 'mysql';

/* CI specific params*/
$_SSS['ci']['db_cache'] = FALSE;

//include any other config files here which have configurations in $_SSS variable
//like email.php etc


As we have now created the tenant specific configuration file we need a mechanism to load the config variables into our ci_app. For with we need to amend the index.php copied from the ci_app directory.
Here are the changes required in the index.php
require_once('./config.php');//first thing, include the tenant_1/config.php here

$system_path = $_SSS['app']['system_path']; //changed from $system_path = 'system';
$application_folder = $_SSS['app']['application_path']; //changed from $application_folder = 'application';
//the above 2 variables are coming from the included tenant_1/config.php file

So now instead of opening the app like this
http://localhost/ci_app we will access it like this http://localhost/tenant_1
And because we are calling the tenant_1 directory we require to have the Codeigniter framework to be available for this directory and this is exactly what we are achieving by doing the above mentioned changes in the index.php file copied from the ci_app directory

The browser will open the index.php which will
  • include the tenant config
  • load the variables required by CI
  • and finally load CI
But hold on we have still a little more to fix to get it running, as we need to pass on the configuration variables to the ci_app/application/config/config.php and ci_app/application/config/database.php files


We need to include the tenant specific config file so that the ci_app config file can access the variable defined there, and this we achieve by changing the following
<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
if (defined('APP_TENANTPATH'))//lets include the tenant_1/config.php

And as we did in the index.php change the variable definition as per your business need


As we did for the config file just above, we need to pass on the DB configuration variables to database.php as well. so here are the changes for it
<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
if (defined('APP_TENANTPATH'))//lets include the tenant_1/config.php

$db['default']['hostname'] = $_SSS['app']['db_host'];
$db['default']['username'] = $_SSS['app']['db_user'];
$db['default']['password'] = $_SSS['app']['db_pass'];
$db['default']['database'] = $_SSS['app']['db_name'];
$db['default']['dbdriver'] = $_SSS['app']['db_driver'];

//we can have more/different config items as required and set in the tenant config file 

This is one way of achieving the Multi-tenancy with CI.

Next thing to do would be to make the asset_url available to the application as the base_url() and the site_url wont be sufficient enough to give the path for tenant linked assets. This can be achieved by
creating a helper function which gets the APP_ASSETURL if it is set. and use this helper function to load the asset files.

Now you just have to replicate the tenant_* folders and change the configs etc to suit the requirements and access the multi-tenancy enabled app like http://localhost/tenant_*
Or create subdomain and link them to tenant_* folders to access something like this

Thanks for reading,

Check my Analytics app here


Pankaj said…
Thank you very much... Very nice explanation and easy to understand. It will be great if we can develop a UI to generate folders, config file and index file. Really helpful. Need to implement same on Bonfire.
Sandeep Rajoria said…
Thanks for the support and the food for thought Pankaj.
I will definitely give it a try.
Visningsnavn said…
Followed your instructions on a blank CI3 site but all i get is Bad Request, Your browser sent a request that this server could not understand.
Unknown said…
Nice Article. best article read in the right time. thank you very much for the article. please keep this great work.
Unknown said…
How can you send me a sample code by picking it up?

Unknown said…
How can you send me a sample code by picking it up?
Kang Endang said…
can you send me the code?
UltraCare PRO said…
Thank you very much... Very nice explanation and easy to understand.
get physiotherapy machine here
Faizan Umer said…
This comment has been removed by the author.
The Pope said…
Can sand deep please contact me on
Atip Nomsiri said…
I can't run my project.
Can you send me a sample code please?

Abdallah mohsen said…
Can you send me a sample code please?
VBloggers said…
Nice info, I am very thankful to you that you have shared this special information with us. I got some different kind of knowledge from your web page, and it is really helpful for everyone. Thanks for share it. Read more info about codeigniter ajax login example
aaronnssd said…
I am very thankful to you for sharing this best knowledge with us. This information is helpful for everyone. So please always share this kind of knowledge with everyone. Thanks. Read more info about Upload Image Preview Tutorial in Laravel
Unknown said…
This comment has been removed by the author.
Unknown said…
can you send a sample code at
Lascode said…
This was extremely helpful. The knowledge you have shared is invaluable.
Regarding the assets path, in my situation I found the symlink() function in PHP to be the solution for my use case.

Popular posts from this blog

Profiling and checking PHP error_reporting in a Codeigniter App, without editing the config!!

Hi all, You must have definitely used the Profiling in Codeigniter and error_reporting many a times in Development and Testing environment, but I am sure you must have missed it on a real Production environment. As there are scenarios, where you want to quickly debug the Production application and find out what PHP errors is the application throwing, check the page profile, that too without putting the time and effort in replicating the whole production environment on your local machine, or perhaps a testing server. This small piece of code(we could perhaps call it a hack), which I have used in almost all of my CI applications, will make your life very easy, without losing anything on the security of the system. Following points, essentially sum up what exactly it does - Check for the dev(or root or admin, whichever name you use for the su access), if it is logged in, as we don't want others to see all the Profile data and other errors. Check for a specific query str

Experience with Repository pattern implementation in Laravel

Hi folks, Today I am gonna be sharing my experience of implementing and working with Repository Design Pattern in Laravel. As you must be aware that Repository Pattern is one of the widely used design patterns  " which separates the logic that retrieves the data and maps it to the entity model from the business logic that acts on the model. In other words, business logic can access the data object without having knowledge of the underlying data access architecture " My first hand experience Around a year ago I started working on a Service Provider App with Laravel as the back-end exposing APIs for the front-ends like the Mobile and Desktop Apps. And like any other architect, while designing this huge looking application I had to take some important decisions on the architectural level. One of them being the buzzing, totally in, Repository Design Pattern bandwagon which everybody in the tech world was taking and if not that, at-least talking about. I went throug