You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Dynamically load development or test default values #266
Using a Rails app as an example, a developer may want to load certain default values when Rails.env.development? and others when running the test suite and Rails.env.test?. Both of these cases should use the same Envfile. So what's the most intuitive way to load different default values based on the environment, keeping in mind that Figaro 2.0 is dropping the explicit Rails dependency?
I'd like to be explicit about what's being loaded and avoid hidden conventions. Think about Bundler and how you source "https://rubygems.org" at the top of every Gemfile. The Bundler team could have made that the default source since it is 95% of the time, but they opted for clarity.
I'd love to get others' thoughts on these two ideas and suggestions for more ideas. Thank you!
defaults makes it unclear what values will actually be loaded.
I think the strategy for loading really depends on if you expect value files to act like cascading stylesheets, where you can provide overrides in special conditions, then multiple DSL source calls makes the most sense. If you expect variables to be more mutually exclusive and independent, then I think a single YAML file with keys makes more sense. I have concerns in either situation.
Environment files that depend on values previously declared in another environment file seems risky and unpredictable. Cascading is tricky if you don't see how things are being sourced. I'd rather see a single file that has all the overrides declared in them so there's fewer places to check to determine where something was sourced.
A single env file that has keyed value sets is nice for seeing what's overridden where, but there's a good chance you might want to have overrides for one environment (test) in source control, but not from another (production). So in that case, I'd rather have separate env files for each environment I'd be loading.
If you're using a single keyed environment file and passing the key in the Envfile, you miss out on cascaded loading unless you combine it with subsequent conditional loading, i.e.
I guess it all depends on what your goals are, but I think separating the idea of defaults and sourced variables is important for the clarifying the ideas in this discussion.
Update: After mulling this over some more, I'm leaning toward a single YAML configuration file with the ability to key the file according to the application environment. To define the application environment (since Figaro will no longer be Rails-dependent), I'm adding the environment method to the DSL. For example:
As for the defaults method naming, I hear you. I'm not sold on it either. I'm not sold on the alternatives set forth yet either. I'll keep rolling that one around.
When it comes to committing multiple default values for a given key, let's say for the development and test environments while keeping the production value out of source control, there are a couple of options:
Load multiple YAML configuration files, some committed and some not.
Allow environment-dependent default values in the envfile.
I'm not sure what to do about this one just yet either. I don't like the idea of multiple YAML configuration files because it's harder to track down what values are where. Plus it's more likely that something that's not supposed to get committed does get committed. Here's what option 2 might look like in practice:
👋 Hello, @laserlemon from 5 years ago! You've finally had some time to think about this some more. 😂 Here's where we're at…
@shekibobo's suggestion of source is so good that I wonder how I never realized it earlier. I also like the environment DSL idea. But I'm definitely second-guessing the hard requirement for a single configuration file.
I'm also not loving the default: { development: "developer", test: "computer" } syntax because it's conceivable that the default value for a variable could be a Hash! So then we'd have to make guesses at the writer's intent. I'd rather build a DSL where there's no guesswork.
So for the purposes of finishing this comment so I can get start my work work day… what about something like this:
# This must be a string, must be sourced from ENV, and must have a default.environmentkey: "APP_ENV",default: "development"# Maybe this file is committed and contains only safe values. It's loaded only# in development and test environments. This file has the lowest precedence# but still beats the per-variable defaults defined in this file.source"env.dev.yml",environments: ["development","test"]# Similar to above. In the test environment, values in this file take precedence# over those in env.dev.yml, because the source is specified later in this file.source"env.test.yml",environment: "test"# This file is not committed and contains the real secrets.source"env.yml"# I can imagine a scenario where folks don't even want to use ENV and would# rather source all of their configuration from files. So maybe it's helpful to# make the ENV source explicit. It would also allow writers to add a file source# with even higher precedence than ENV if they so choose. That might be a# little unconventional, but I don't see a reason to forbid it.source:envstring:hello,default: "world"
Activity
shekibobo commentedon Jul 3, 2017
Priority of variables loaded, from lowest to highest:
Envfile, i.e.string :foo, default: "Foo".env.ymlfiles. Last declaration wins, overriding previous declarations of the same named variable.ENVvariables declared on the system.With this in mind, I don't think
defaultsis a confusing method name. I'd suggest something that suggests the precedence of the files being loaded:defaultsmakes it unclear what values will actually be loaded.I think the strategy for loading really depends on if you expect value files to act like cascading stylesheets, where you can provide overrides in special conditions, then multiple DSL
sourcecalls makes the most sense. If you expect variables to be more mutually exclusive and independent, then I think a single YAML file with keys makes more sense. I have concerns in either situation.test) in source control, but not from another (production). So in that case, I'd rather have separate env files for each environment I'd be loading.Envfile, you miss out on cascaded loading unless you combine it with subsequent conditional loading, i.e.I guess it all depends on what your goals are, but I think separating the idea of
defaultsandsourcedvariables is important for the clarifying the ideas in this discussion.laserlemon commentedon Dec 27, 2017
Update: After mulling this over some more, I'm leaning toward a single YAML configuration file with the ability to key the file according to the application environment. To define the application environment (since Figaro will no longer be Rails-dependent), I'm adding the
environmentmethod to the DSL. For example:As for the
defaultsmethod naming, I hear you. I'm not sold on it either. I'm not sold on the alternatives set forth yet either. I'll keep rolling that one around.When it comes to committing multiple default values for a given key, let's say for the
developmentandtestenvironments while keeping theproductionvalue out of source control, there are a couple of options:I'm not sure what to do about this one just yet either. I don't like the idea of multiple YAML configuration files because it's harder to track down what values are where. Plus it's more likely that something that's not supposed to get committed does get committed. Here's what option 2 might look like in practice:
Anyway, just dumping some thoughts here. Feel free to chime in!
laserlemon commentedon Jul 17, 2025
👋 Hello, @laserlemon from 5 years ago! You've finally had some time to think about this some more. 😂 Here's where we're at…
@shekibobo's suggestion of
sourceis so good that I wonder how I never realized it earlier. I also like theenvironmentDSL idea. But I'm definitely second-guessing the hard requirement for a single configuration file.I'm also not loving the
default: { development: "developer", test: "computer" }syntax because it's conceivable that the default value for a variable could be aHash! So then we'd have to make guesses at the writer's intent. I'd rather build a DSL where there's no guesswork.So for the purposes of finishing this comment so I can get start my work work day… what about something like this: