Basically, one of the greatest questions of all time: What are some ways you're using settings.php in your development/staging workflow?

Right now, I have my settings.php file set up like the following, and I base my development on the server's $HOST directive—meaning I can work on dev.example.com for the development (shared) server, local.example.com for my local computer (and other dev's local code checkouts), and www.example.com (or just example.com) for the live site.

(This code is in the 'Database settings' section of settings.php):

$host = $_SERVER['HTTP_HOST'];
$base_url = 'http://'.$host;
$cookie_domain = $host;

switch($host) {
  case 'example.com': # Production server
    $db_url = 'mysqli://prod_sql_user:password@127.0.0.1/prod_db';
    $update_free_access = FALSE;
    $conf = array (
      // Set production config options here...
      'example_setting' => 0,
    );
    break;

  case 'dev.example.com': # Development server
    $db_url = 'mysqli://dev_sql_user:password@127.0.0.1/dev_db';
    $update_free_access = FALSE;
    $conf = array (
      // Set production config options here...
      'example_setting' => 0,
    );
    break;

  case 'local.example.com': # Local server
    $db_url = 'mysqli://local_sql_user:password@127.0.0.1/local_db';
    $update_free_access = FALSE;
    $conf = array (
      // Set production config options here...
      'example_setting' => 0,
      // Turn off most core caching.
      'cache_inc' => 'includes/cache.inc',
      'cache' => CACHE_DISABLED,
    );
    break;

}
?>

This works pretty well for most purposes, but it means we have a lot of extraneous code sitting around in our shared settings.php file... is there a better way?

up vote 68 down vote accepted

What I do is separating that file into a settings.php and a local.settings.php.

At the end of settings.php is the following code:

if (file_exists(dirname(__FILE__) . '/local.settings.php')) {
  include dirname(__FILE__) . '/local.settings.php';
}

The local file is then excluded from whatever VCS you are using. The advantage is that you can put settings which are common over all instances in settings.php and have that versioned/distributed automatically and keep the local stuff in local.settings.php.

  • 2
    This is actually the strategy used on drupal.org itself and we use consistently at Palantir.net. For a bikeshed, I recommend using 'settings.local.php' as the filename as it matches the pattern set by 'settings.default.php'. – Dave Reid Mar 2 '11 at 21:26
  • 1
    I've created a gist for this: gist.github.com/1235389 since i've been using this more and more frequently – chrisjlee Sep 22 '11 at 17:22
  • 4
    Note: Drupal 8 has now added a similar snippet to the settings file by default, you just need to uncomment it: drupal.org/node/1118520 – Berdir Jun 1 '12 at 17:45
  • 1
    @DaveReid: the pattern is set by 'default.settings.php' not by 'settings.default.php'. – iconoclast Jul 31 '12 at 19:29
  • 1
    For funsies you could use (__DIR__) instead of dirname(__FILE__). They are equivalent. – cdmo Jul 26 '13 at 13:33

This seems like you're reinventing Drupal's built in multisite functionality.

Personally, I keep all standard themes and modules for the site in sites/all, and then have sites/dev.example.com and sites/example.com.

As an added bonus you can then have different files folders for each site, and you can add any development modules to sites/dev.example.com/modules as well.

  • That makes some sense, but I have a few sites where there are 5-10 multisite folders already, and having all the themes for those sites in sites/all/themes can be quite annoying. Not to mention my typical use of custom.module for each site. I guess I could use sitename_custom.module instead :-/ – geerlingguy Mar 2 '11 at 21:02
  • 2
    You could always try using symbolic links from the sites/dev.example.com/modules to sites/example.com/modules – Paul Jones Mar 2 '11 at 21:04
  • Accepting this answer - I'm going to try this on the site I'm currently working on. Looks like a good fit for my workflow. – geerlingguy Mar 2 '11 at 21:16
  • 9
    I think this is actually a poor way to handle dev and staging environments because they aren't actually different/separate sites, just different versions of the same site. In this case you would very much want to avoid having separate files for each site. I'd very much recommend using the method mentioned below where settings.php is versioned and settings specific to each site (DB settings) are put in a local.settings.php that is not versioned. – Mikey P Mar 3 '11 at 3:46
  • 1
    @Mikey P - both solutions are valid—I think it's mostly up to personal/team preference here... there are tradeoffs with either approach, in my opinion. – geerlingguy Mar 3 '11 at 18:01

I prefer to ignore the file locally (using a .gitignore file in git) and then keep separate versions if the file on each host.

  • 1
    This is an interesting solution, though I do like tracking settings.php in git (some bugs I've had crop up are due to setting.php changes...). Is there a way I could have my local git checkout replace that file with my own (besides having me copy in my own file)? – geerlingguy Mar 2 '11 at 21:00
  • 1
    That's what I do too. Files with configuration data, especially with database credentials have no place in the VCS. – mmartinov Mar 3 '11 at 0:37
  • @geerlingguy yes you can. Please read my update (if it'll be published ;) – sobi3ch Apr 3 '15 at 10:32
  • @martin I agree, but let's don't forget we can have SPECIAL separate repo only for THIS file! You can read it in my update. – sobi3ch Apr 3 '15 at 10:34

I tend to always set up DNS or host file entries and use

dev.example.com
staging.example.com

and

example.com

Then I have completely separate settings file directories with differing files directories. For instance ./sites/dev.example.com/files

  • The problem I see with that approach is that I often have a /themes/ and /modules/ directory that I use for each site (often in a multisite setup), and since I need to use those site-specific modules and themes for local, dev and production, I can't just do hosts/multisite like that :-/ – geerlingguy Mar 2 '11 at 20:58
  • Good point. I guess I left out that I symlink that stuff in. – Stewart Robinson Mar 2 '11 at 21:09
  • You can create a symlink and share themes and modules folders that way. So basically you main folder will be a production folder and then from it you can create a symlinks to stage and dev and local. – gansbrest Mar 2 '11 at 21:10

Why not have a few folders based on the development host name?

Example

  • sites/dev1.domain.com
  • sites/dev2.domain.com
  • sites/dev3.domain.com
  • sites/www.domain.com

Each with their own settings file and db_url.

  • Potential problem: Files saved/uploaded in one site folder will not be accessible to another. – Greg Mar 2 '11 at 20:58
  • See my reply to @Stewart :) – geerlingguy Mar 2 '11 at 20:59
  • Create symlinks to the central files folder – Kevin Mar 2 '11 at 21:09

If the only things changing are the database credentials, then you can set environment variables in your local (and staging/production) virtual host config or in a .htaccess a folder above your web root. Here's a simple example:

/var/www/example.com/drupal-resides-here

I can then create a .htaccess file here:

/var/www/example.com/.htaccess

which has the following code:

SetEnv DB1_USER my_local_user
SetEnv DB1_PASS my_local_pass
SetEnv DB1_HOST my_local_host
SetEnv DB1_NAME my_local_dbname

Then in /var/www/example.com/drupal-resides-here/sites/default/settings.php (or whatever) you can grab the db credentials like:

$db_url = "mysql://{$_SERVER['DB1_USER']}:{$_SERVER['DB1_PASS']}@{$_SERVER['DB1_HOST']}:{$_SERVER['DB1_PORT']}/{$_SERVER['DB1_NAME']}";

This lets multiple developers run things locally and you can push to staging / production while still tracking settings.php (there are more things in there than just the database credentials...). You also wouldn't have to keep track of multiple settings.php files.

  • I personally think this is the best way to go. However, our set up we add the SetEnv statements to the apache config. Makes it a bit more secure. – Scott Joudry Dec 4 '13 at 21:32
  • That's an interesting use for .htaccess and variable storage. But what about when you run drush up --y? That will overwrite your base .htaccess file. – Screenack Jan 8 '14 at 1:46
  • This is done in an .htaccess file a level above webroot. For example, /var/www/.htaccess stores these directives, and /var/www/drupal/.htaccess would be Drupal's .htaccess. You could also just put it in the Apache virtual host configuration, which is even nicer. Regardless of any of that, we almost always have custom stuff in the webroot's .htaccess and therefore if we update Drupal we need to compare the .htaccess changes with Git. – Charlie Schliesser Jan 8 '14 at 16:43

Simplest and most efficient solution that is just one line is the following. Just include it in the last line of your settings.php file:

@include('settings.local.php');

The @ symbol in the front just means don't display any error even if it doesnt find that file. Typical setup's like this involve a conditional to check if the file is there. This accomplishes it in one line without it.

http://php.net/manual/en/language.operators.errorcontrol.php

Also known as the STFU PHP operator.

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.