My 2c: I tent to prefer explicitness for env vars, rather than having things magically get loaded. I’ve seen and used this mechanism before:
export $(cat .env | xargs) && mix phx.server
direnv works well, but assumes folks have it set up (most do). The above is more explicit in my opinion. I don’t mind the verbosity, mostly due to me rarely having to type that out (always on a readme or in a shell history somewhere).
When working with others, there is usually something on the readme that will help (including yourself when you forget ) As far as the mechanics:
There is usually a .env.example that is committed to the repo (example)
I don’t know why I never thought of this—it seems so obvious, lol.
The dev script still comes in handy, at least for one project, where I need to start up multiple nodes. Of course, Docker is probably the “real” answer there, but I’m stubborn. Maybe there is another way? Though this is getting a little off topic of purely ENV vars.
I use (and love) direnv, but for working with others, I find that dotenvy is a good solution with less friction than direnv.
It’s another dependency, but it gets rolled in with the others when you run mix deps.get. Plus it works in all environments, instead of only ones where direnv is installed (CI, shared dev boxes, etc.).
I’ve encountered the custom config.exs strategy mentioned by @D4no0, and I’m not a fan of the concept. Dotenv files are closer to a “universal” configuration system, so that’s a big plus for me. It allows me to share a config system between my Elixir project, my Docker Compose config, etc.
I say “probably” because I tend to avoid Docker myself. I don’t have anything against it, I just spent a few years entirely disinterested in anything ops-related. That’s changing, however, so I will probably reacquaint myself. At a past job we used Docker for development (I just didn’t do any of the setup). I actually have no idea why anyone would think it’s a bad idea as it went quite smoothly for us. The only thing I can think of is that it’s memory intensive on macos so maybe with larger apps that becomes more of a thing. I have yet to watch the video you shared but I’ll add it to my queue.
No idea. You’d have to ask the ops team at that job who mandated that I didn’t notice recomp times to be too bad but the whole thing was a Rube Goldberg Machine anyway so I always chalked up the slight slowness to that, but it wasn’t so bad. It can definitely make sense for people working on multiple projects using different version of Postgres, for example, though I’m never in that situation myself. But ya, it certainly didn’t feel necessary working on a company machine dedicated to working on one project.
I heard the argument that using Docker in development can prevent bugs that are caused by differences in OS. And more generally the argument that the closer the development environment is to the production environment, the smaller the potential for issues when pushing to production.
I don’t really have an opinion about that argument myself. But I’m interested in the topic. Do these arguments make sense and are they valid in practice?
Usually if you have a dockerized prod, your CI that will run tests will be in docker containers too, so as long as those tests run successfully on CI, there should be absolute no problems.
I don’t think so, as long as your setup is to create a release, and you are using the same versions of elixir and OTP on prod as well as dev, everything will work the same.
The only real benefit I see is the fact that you can preinstall and configure some settings in a repeatable way, literally the fact why docker is useful in the first place, however in practice I’ve never had projects requiring anything more than installation of some local dependencies.
I did have some ecto bugs on the last project I worked on, setting up sandbox for testing. Those surfaced only in the docker image on CI, no idea what that was about, a possible explanation would be that we were using a old version of exqlite.
You can either run a Docker container with Elixir installed in the docker compose setup and share the project folder as a volume. In that case, you just run mix phx.server within the Docker container instead of locally on your machine (probably with an entrypoint script). So you don’t have to rebuild the image all the time.
But nowadays, I usually just have a docker compose setup for Postgres, Minio, or whatever services I need for development, and run the Phoenix server locally. That’s a bit less of a hassle.
If you need secrets in your local environment and you use a password manager with a CLI (like 1password or bitwarden), you can use that to set the environment variables. This has the advantage that you can just add a shell script to set those variables, and the script can safely be committed. Then you just have to make sure every team member has access to the shared vault.