Specify secrets via env. variables only in production?

Has it now become required to pass secrets via enviromental variables and via no other way? If not, why the “raise”?

# config/runtime.exs

if config_env() == :prod do
    database_url =
        System.get_env("DATABASE_URL") ||
            raise """
            environment variable DATABASE_URL is missing.
            For example: ecto://USER:PASS@HOST/DATABASE

What if I want to use /config/prod.secret.exs instead?

It raises because the variable is required. Otherwise the app won’t start.
But you can use any way you want to configure the app.

You’ve stated the obvious, but that hasn’t answered my question.

I’m not asking “what it is”, I’m asking “what’s changed” and whether using the prod.secret.exs will work. If so, how? Given that I don’t want to have to edit that code with “raise” in config/runtime.exs manually, nor remove it.

The prod.secret.exs approach never supported runtime configuration, nor did it follow common configuration conventions, which is why it has been removed from the generators. But if it worked for you before you can continue using it.

1 Like

Then it seems I misunderstood your question.

Has it now become required to pass secrets via enviromental variables and via no other way?

No. It is not requires to pass the secret via environmental variables. You can pull them in any way that fits your use case.

If not, why the “raise”?

As noted by @LostKobrakai, config/runtime.exs is now the preferred way to configure the app. You can find the rationale here.

1 Like

Alright. But now I’ll have to remove that “raise” from “runtime.exs” each time I create a new project

Yeah, just like previously many people removed the prod.secret.exs on every project, because it didn’t match their workflow. There’s not going to be a perfect solution for everyone. At least the current one should be fitting for a larger group of people, given it aligns more with common industry practices.


For instance, what are the ways?

Note that I may have tens of Elixir/Phoenix applications on the same machine in production, therefore specifying env. variables in ~/.bash_profile, ~/.profile or any OS-specific, standard file absolutely won’t work for me.

There are many ways of defining env variables, which are specific to the system being executed as opposed to a user or the whole OS. E.g. in systemd you can define env variables per startable unit.

1 Like

Then I’ll have to chain myself to using systemd?

The thing is:

  • Specifying env. variables on a physical machine itselfabsolutely won’t work for me.

  • Whereas specifying env. variables in a project/repository, in secret file(s), and adding file(s) into .gitignore – will work.

However, because of that “runtime” so-called “improvement” thing I’ll have to edit a newly generate code each time, in order to remove those “raise”. Huh?

  • Read config from a local file (INI, JSON, YAML, TOML, etc.),
  • Read config from a remote service,
  • Continue using prod.secrets.exs.

You have to decide yourself what works for you best.

No, you don’t. You can:

  • Use the older generator,
  • Roll your own mix *.gen task,
  • Use VCS (git apply) to layer your own changes on top of the generated code.

There are options if you would focus on them instead.

  1. You can’t expect Phoenix does everything for us. It just provides general solutions. If you have any special requirements which aren’t provided by Phoenix, implement it by yourself.

  2. You can load config from anywhere via ConfigProvider. There’s a working example in Oban’s doc - Release Configuration — Oban v2.12.0. Check it out.

I already answered you in reddit but since you ask the same question it may be worth doing it here as well.

You complain that the default generated files do not correspond with what you want, but also complain that you have to make changes to the generated files to get what you want.

This is not constructive.

If you have tens of phoenix applications where changing the configuration represents a big part of the work, then I guess those applications are fairly identical, and you should quickly find a way to automate the migration from generated files to your custom configuration layout. Like cp a template secret.exs file and rm runtime.exs in a bash script.

If they are not that much identical, then changing the config, a five minutes task, should represent 0.001% of the work on those apps, and that is a thing that everyone does because in general apps require much more environment variables than those present in the default setup.

The bottom line is that as long as mix phx.new does not generate exactly what you need, you will have to do some work. This is just logical.

The config is Elixir code, you can do anything you want in there. People gave you many possible solutions in this thread. You can even keep the generated runtime.exs and create a start.sh script with a single line like this: PORT=4000 DATABASE_URL="ecto://blablabla" mix phx.server.

1 Like

So I’ll have to introduce in my project yet another dependency that fixes what hhs always worked well?

It has been mentioned a few times already that you can just continue to use the existing approach just fine – albeit with manually creating the config file and linking to it. It has also been mentioned that the previous approach – while fine for you – wasn’t fine for a lot of other people.

At this point I’m failing to see which point you’re trying to make tbh.


If you aren’t going to even read the links provided before complaining about them you’re going to have your posts go through a moderation queue. ConfigProvider is part of the standard library, it is not another dependency.