Here’s a handy tip: create Phoenix configurations that live only on your machine, not in version control.
I use this for setting machine-specific domain names. It’s ideal for any development settings that shouldn’t live in your shared repository.
First, add this snippet at the bottom of config.exs
:
if File.exists?("#{__DIR__}/#{config_env()}.local.exs") do
import_config "#{config_env()}.local.exs"
end
Create a file named dev.local.exs
and Phoenix will load it. Add this to your .gitignore
to keep it local:
# Ignore local environment configs
*.local.exs
Your machine-specific settings won’t touch production or bother teammates. Common uses:
- Local database credentials
- Custom domain names (like
dev.localhost
)
- Local service endpoints
- Personal log levels
Everyone on your team can customize their environment without stepping on each other’s toes. Enjoy!
While the standard ElixirLS installation works well for most developers, running it from source provides access to the latest features and improvements. Recently, after discussing this setup with a colleague, I realized others might benefit from learning how to implement this configuration.
Before proceeding, ensure you have Erlang and Elixir installed on your system. While I personally use Mise for version management, asdf works as well.
Begin by cloning the ElixirLS repository and installing its dependencies:
git clone [email protected]:elixir-lsp/elixir-ls.git
cd elixir-ls
mix deps.get
Next, compile and install ElixirLS. I recommend storing it in ~/.local/share
for better organization. The installation commands vary slightly depending on your shell:
For Fish shell users:
env MIX_ENV=prod mix compile
env MIX_ENV=prod mix elixir_ls.release2 -o ~/.local/share/elixir-ls
For Bash or ZSH users:
MIX_ENV=prod mix compile
MIX_ENV=prod mix elixir_ls.release2 -o ~/.local/share/elixir-ls
Editor Configuration
After installation, the executables will be available in ~/.local/share/elixir-ls
. You’ll need to configure your editor to use this installation.
For Zed, add the following to your configuration:
"lsp": {
"elixir-ls": {
"binary": {
"path": "/Users/<you>/.local/share/elixir-ls/language_server.sh"
}
}
}
- Neovim users can reference my configuration on GitHub.
- VSCode users should update the
elixirLS.languageServerOverridePath
setting.
To maintain the latest version of ElixirLS, simply pull the latest changes from the repository and recompile:
cd elixir-ls
git pull
MIX_ENV=prod mix compile
MIX_ENV=prod mix elixir_ls.release -o ~/.local/share/elixir-ls
This setup ensures you always have access to the most recent ElixirLS features and improvements while maintaining a clean, organized development environment.
In my previous note Shorter feedback loops with Elixir tests I already described how to run tests in Elixir, where it only runs the failed tests. Below is what I put in my mix.exs
file to have faster feedback loops when testing:
defp aliases do
[
...
"test.failed": ["test --failed --max-failures 1"],
]
end
# Make sure the alias runs in the test MIX_ENV environment.
def cli do
[preferred_envs: ["test.failed": :test]]
end
This will create a new alias test.failed
that will run only the failed tests and stop after the first failure. This is useful when you are working on a specific test and you want to run it quickly without running all the tests.
For an exercism exercise I wanted to do multiplication with the pipe operator, and simply using *
does not work, neither does (*)
.
Now, it turns out the arithmetic operations are functions part of the Kernel
module, and you can also call them as an actual function with Kernel.*(2, 2)
, which is equal to writing 2 * 2
.
This enables you do do arithmetic as part of the pipe operation, see:
def monthly_rate(hourly_rate, discount) do
hourly_rate
|> daily_rate
|> apply_discount(discount)
|> Kernel.*(22)
|> ceil()
end
In Ruby, you have the --fail-fast
flag, which stops running the test suite at the first failed test. Convenient to get shorter feedback loops, with a long running test suite.
In Elixir, you can achieve the same with:
mix test --max-failures 1
And then when a test fails, you fix it, and make sure that it works with:
mix test --failed
That makes for shorter feedback loops!
The following is what I use to setup Elixir on my machines, where I want to make sure that I can jump to all definitions of Elixir library functions.
First, I install asdf. I go the Homebrew and Fish route, but you can also do it from the source and use your shell of choice.
Before I install Erlang, I make sure to set the right flags, because I don’t want Java or build any GUI stuff:
KERL_BUILD_DOCS="yes"
KERL_CONFIGURE_OPTIONS="--disable-debug --without-javac --without-wx"
After that, I go to the asdf-erlang repository, check that I have all the build requirements and install Erlang with:
asdf plugin add erlang https://github.com/asdf-vm/asdf-erlang.git
# check available Erlang versions
asdf list all erlang
# install the latest version
asdf install erlang 26.2.4
# enable it globally
asdf global erlang 26.2.4
Now, let’s install Elixir. Go to the asdf-elixir repository, make sure you have unzip installed, and do the following.
asdf plugin-add elixir https://github.com/asdf-vm/asdf-elixir.git
# check all available versions
asdf list all elixir
# install the latest version, but! Install by source, so we can jump to the definition of Elixir functions
asdf install elixir ref:v1.16.2
# enable elixir globally
asdf global elixir ref:v1.16.2
Now, it says it in the comments, but the important difference is that I install Elixir by reference instead of the pre-compiled versions because I also like to be able to jump to definitions of Elixir library functions.