Multi-config setup


What’s the best way to handle an application for multiple environments/scenarios?

Say, I have dev, qa and production environments; I have a separate config/test.php for repeatable testing. The setup should recognize the current environment and use appropriate config settings.

Multiple configs by $_SERVER[‘HTTP_HOST’]? Tried that, not convenient (dev environment from work and home have different value.

Environment vars? Cumbersome.


a few readings to begin with:

Bettor, thanks.

I’ve seen both of those. The first one doesn’t answer the first requirement - automatic desicion-making. Second one is better, but is not robust enough. If I have four environments - dev, qa, stage and prod, I have to change four entry points - index.php, index-test.php, yiic.php and bootstrap.php to cover everything and there would be too much switch variants… Not flexible.

What if I’m in QA and something is just not working? I can try my prepared unit tests, but - alas - they’re looking at the test database with fixtures and such. I want the flexibility to run some tests against test db, some against live one. And I need the flexibility to quickly run tests at will without changing the files, any of them. See where I’m going?

Nonetheless, really appreciate the answer.

More ideas?

Ok, here’s what I’ve come up with:

  1. In all console.php, main.php and test.php the database thing I’m defining as follows:


		'db' => require(dirname(__FILE__).'/'.Y_DB.'_db.php'),

  1. under protected.config I’ve created files dev_db.php, test_db.php, etc. as such:


return array(

	'class' => 'system.db.CDbConnection',

	'connectionString' => 'mysql:host=localhost;dbname=appdatabase_dev',



and appdatabase_dev becomes app database_test for test.php, appdatabase_live to be used in production environment.

  1. now there’s a need to automatically select proper Y_DB. There’s three things to consider:
  • based on the operational environment (dev server, qa server, …)

  • there should be a way to override the database for the current environment.

  • the application can be run as a web app, as a cron script, as a phpunit test

Phew, too many ‘whishes’, not?

Here’s my index.php:


// where we at?



	&& in_array(getenv('Y_ENV'), array('dev', 'qa', 'stage', 'live'))

	? getenv('Y_ENV')

	: 'dev');

define('Y_DB', getenv('Y_DB') ? getenv('Y_DB') : ENVIRONMENT);

// load an environment-specific config file

//$config = dirname(__FILE__) . "/../protected/config/" . ENVIRONMENT . '.php';

// load main config file

$config = dirname(__FILE__) . "/../protected/config/main.php";

// set important paths


// environment-specific stuff (fine-tuning things)



	case 'live':

	case 'qa':


	case 'dev':

		defined('YII_DEBUG') or define('YII_DEBUG',true);

		defined('YII_TRACE_LEVEL') or define('YII_TRACE_LEVEL',3);




// run the app or print the $config variable, up to you.


//print "config: $config\n";

Other entry points are similar to index.php. index-test.php, for instance, loading test.php instead of index.php. A commented line

//$config = dirname(__FILE__) . "/../protected/config/" . ENVIRONMENT . '.php';

technically allows to load an environment-specific config file, but at the moment it is overkill for me.

Ok, now the question is how to do the automatic switching (i.e. where these env. vars are coming from)?

Here it is.

On every server set the Y_ENV var at these locations:

APACHE: /etc/apache2/envvars

CRON /etc/crontab

BASH: /etc/environment

for instance,


It might be one of dev, prod, qa.

This is it. You run your app from web, from console, from phpunit and it uses whatever environment is appropriate.

Now, how to overwrite the database in case you want to temporarily switch to another database?


shell# Y_DB=db_qa phpunit unit/testWhatever.php

The same way it is possible to run migrate scripts on every server without changing config files.

Excellent. Why not document it in a wiki so we all can benefit from your idea ;)

Well, I haven’t fully tested the code, just come up with the idea a few minutes ago. Definitely will put it up there for everyone once it is finalized and documented. Besides, code shows that I moved protected/ and framework/ around a bit, so that needs to be formalized as well.