Hi!
I want to do something like this.
if MIX_ENV == “dev” do
do if in local dev environment
else
do if in production environment
end
Is this possible?
Hi!
I want to do something like this.
if MIX_ENV == “dev” do
do if in local dev environment
else
do if in production environment
end
Is this possible?
In my experience, this a bad idea and there are many times that this can be avoided (but not always).
First of all, Mix is a tool which is not available in a release, so it can be dangerous if you use in dev.
I don’t know what you are trying to do, but for example, if you don’t want to send emails in dev, it should have its own configuration. Maybe this configuration relays on an environment variable in production, but it should not have a generic name, it would be better something like MAIL_CONFIG
.
Maybe the following links help:
i tried this in config.exs and it works
if "#{Mix.env}" === "dev" do
IO.puts "I am in dev environment"
end
In the config, this construct is safe to use, but I’m wondering why you don’t use environment specific config files?
Also instead of stringifying you should compare atoms directly: Mix.env() == :dev
You can add config :myapp, :environment, :dev
to dev.exs
and config :myapp, :environment, :prod
to prod.exs
and then in your function:
if (Application.get_env(:myapp, :environment) == :prod) do
# prod branch
else
# dev/test branch
end
If you want to do it at runtime
if unquote(Mix.env == :dev) do # would compile to true or false
# ...
else
# ...
end
However I prefer to compile different functions / bodies depending on the mix env / runtime version, rather than using if
branching inside of them.
defmodule SomeModule do
if Mix.env == :test do
def func(), do: :ok
else
def func(), do: # actually do soemthing
end
end
but I use it very rarely (mostly in routers / plug pipelines), something like a protocol is usually a cleaner approach.
Why not
if Mix.env == :dev do
IO.puts "I am in dev environment"
end
?
Since config.exs is only evaluated during compilation, it’s safe to call Mix.env
without unquoting there.
From what I understand, he wants his code to behave differently when deployed.
As @alexcastano mentioned, Mix is not available in a release. It will work while you run in dev but will not work in the production environment.
That’s why you should use unquote(Mix.env == :dev)
during runtime … And config.exs is not being evaluated in a release, so it doesn’t matter.
In my case, I wanted to read DB username and password from env variables.
I have experience with Nodejs that you can put a .env file in root project and every time the projects loads, the variables are loaded.
This is what I did in Phonix for that:
I have created a dev.secret.exs in config folder that is ignored in git.
after that I put my env variables in it like :
System.put_env("DATABASE_USER", "something")
and then imported this file on top of the dev.exs file with condition of dev mode:
if Mix.env == :dev do
import_config "dev.secret.exs"
end
Secrets in Phoenix shouldn’t go in any configuration that is not the config/runtime.exs
, otherwise they will be shipped inside the release, therefore they can be leaked during CI/CD pipelines or deployment process. They can also be extracted from inside the release with reverse engineering techniques.
Using config/runtime.exs
with system environment variables guarantees that secrets will always be retrieved from the server running the release.
# config/runtime.exs
config :cms, Cms.Repo,
username: System.fetch_env!("POSTGRES_USER"),
password: System.fetch_env!("POSTGRES_PASSWORD"),
database: System.fetch_env!("POSTGRES_DB") <> "_" <> Atom.to_string(config_env()),
# database: System.fetch_env!("POSTGRES_DB"),
hostname: System.fetch_env!("POSTGRES_HOSTNAME"),
show_sensitive_data_on_connection_error: true,
pool_size: 10
if config_env() == :prod do
config :cms, Cms.Repo,
show_sensitive_data_on_connection_error: false
end
The .env
file:
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_DB=cms4devs
POSTGRES_HOSTNAME=database
Export the secrets with:
export $(grep -v '^#' .env | xargs -0)
or if using docker-composer.yml
:
env_file:
- .env
Is there anyway to run export $(grep -v '^#' .env | xargs -0)
in phoenix runtime?
I mean when you run mix phx.server some how this export command get run
I have a config system based on config/runtime.exs
and I use DotenvParser to load configuration from .env
during development (but no reason you couldn’t use it in production too).
Here’s a blog post about it for more details: Simple Configuration Setup for Elixir Projects (v1.11+) – Random Notes
Disclaimer: I wrote DotenvParser.
You can also write your .env
file using export
statements, so instead of having VARIABLE="something"
, you would use export VARIABLE="something"
and then run . .env && iex -S mix phx.server
You could also add an alias to your shell to do that, for instance, if using bash, on your .bashrc
file, adding alias iexphx=". .env && iex -S mix phx.server"
(refresh the shell after saving, with exec bash
) and then you can just run iexphx
from the command line when inside a working directory.
I used this trick in the past, but I forgot about it. Thanks for reviving it
I am using docker for any programming language and developer tool I need to run in my computer for several years now, thus the .env
file cannot use the trick you mention, but for others not using docker it makes all the sense and is indeed better, especially with your recommended alias
Learned another trick
I usually refresh the shell with . ~/.zshrc
or . ~/.bashrc
.
That works too!