Question

What is a good way to set up a project in Scala which uses different configuration depending on environments.

I need to specifically have different databases for development, test and production environment (similar to what is done in Rails)

Was it helpful?

Solution

Another strategy I'm using consists of using includes. I usually store my DEV settings in the default application.conf file then I create a new conf file for other environments and include the default one.

Let's say my DEV conf application.conf looks like this:

myapp {
    server-address = "localhost"
    server-port = 9000

    some-other-setting = "cool !"
}

Then for the PROD, I could have another file called prod.conf:

include "application"

# override default (DEV) settings
myapp {
    server-address = ${PROD_SERVER_HOSTNAME}
    server-port = ${PROD_SERVER_PORT}
}

Note that I override only the settings that change in the PROD environment (some-other-setting is thus the same as in DEV).

The config bootstrap code doesn't test anything

...
val conf = ConfigFactory.load()
...

To switch from the DEV to the PROD conf, simply pass a system property with the name of the config file to load:

java -Dconfig.resource=prod.conf ...

In DEV, no need to pass it since application.conf will be loaded by default.

So here we're using Typesafe Config's default loading mechanism to achieve this.

I've created a simple project to demonstrate this technique. Feel free to clone and experiment.

OTHER TIPS

Use typesafe Config. Create a Config object like this:

import com.typesafe.config._

object Config {
  val env = if (System.getenv("SCALA_ENV") == null) "development" else System.getenv("SCALA_ENV")

  val conf = ConfigFactory.load()
  def apply() = conf.getConfig(env)
}

Then create the application.conf file in src/main/resources folder:

development {
  your_app {
    databaseUrl = "jdbc:mysql://localhost:3306/dev_db"
    databaseUser = "xxxx"
    databasePassword = "xxxx"
  }
}
test {
  your_app {
    databaseUrl = "jdbc:mysql://localhost:3306/test_db"
    databaseUser = "xxxxx"
    databasePassword = "xxxx"
  }
}

Now from anywhere in your application, you can access configuration:

Config().getString("your_app.databaseUrl")

If you have your environment set up (e.g. export SCALA_ENV=test) when you run your application, it will consider the right configuration section. The default is development

I wasn't happy with how Daniel Cukiers solution did not allow defaults and overrides, so I changed it around to make full use of those.

The only configuration you have to do is set a ENVIRONMENT variable on the system (defaults to 'dev' if none is set)

(Java solution, compatible with Scala):

import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;

public class MyCompanyConfig {
    public final static Config base = ConfigFactory.load().getConfig("mycompany");
    public final static String environment = System.getenv("ENVIRONMENT") == null ? "dev" : System.getenv("ENVIRONMENT");

    /**
     * Returns a subtree of the base configuration with environment settings applied.
     *
     * @param setting The subtree to return config for.
     * @return A config with base in given setting, with environment modifications applied.
     */
    public static Config load(String setting) {

        Config config = base.getConfig(setting);

        if (config.hasPath(environment)) {
            return config.getConfig(environment).withFallback(config);
        }

        return config;
    }
}

This allows a single reference.conf in a library looking like this:

mycompany.module1 {
    setting1 : "adefaultvalue"
    url : "localhost"

    test {
        // will be used where ENVIRONMENT="test"
        url : "test.mycompany.com"
    }

    prod {
        // will be used where ENVIRONMENT="prod"
        setting1 : "changethedefault"
        url : "www.mycompany.com"
    }
}

Usage:

Config conf = MyCompanyConfig.load("module1")
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top