Using mix aliases to improve your workflow
When developers onboard new projects, we are uniquely positioned to help improve the onboarding experience for future developers. So, when I join a new project, I relish the opportunity to clarify and simplify setup instructions.
Recently, I joined a new project and took a look at the setup instructions:
## Dev setup To set up the project, run: mix deps.get mix event_store.create mix event_store.init mix ecto.create -r R1 mix ecto.create -r R2 mix ecto.migrate -r R1
So, after getting the project’s dependencies, we create an event store and initialize it. Then, we create two ecto repos (R1 and R2) and migrate R1. R2 is a read-only repo, so it doesn’t need to be migrated.
That’s six steps. And they’re all things we could script. So, I asked myself,
could we consolidate those steps into a single
mix setup step?
I frequently use mix aliases to simplify my workflow, so I checked the
mix.exs file to see what was there. To my surprise, the project
didn’t have any aliases defined. And that was an opportunity for improvement.
I added the
aliases entry in
project and defined a
def project do [ ... aliases: aliases() ] end defp aliases do [ setup: ["deps.get", "event_store.setup", "ecto.setup"], "event_store.setup": ["event_store.create", "event_store.init"], "ecto.setup": ["ecto.create -r R1", "ecto.create -r R2", "ecto.migrate -r R1"] ] end
Taking inspiration from other Phoenix apps, I defined three aliases:
ecto.setup. We can run
mix event_store.setup and
mix ecto.setup separately if we ever need to, but running
mix setup performs
all the desired actions.
Having done that, I could then change the setup to be a single command:
## Dev setup To set up the project, run: - - mix deps.get - mix event_store.create - mix event_store.init - mix ecto.create -r R1 - mix ecto.migrate -r R1 - mix ecto.create -r R2 + mix setup
As I read further down the README, I noticed we had a similar setup with tests:
## Test setup MIX_ENV=test mix ecto.create -r R1 MIX_ENV=test mix ecto.create -r R2 MIX_ENV=test mix ecto.migrate -r R1
I could have created a
test.setup alias, but instead, I took inspiration from
Phoenix apps to create an improved
mix test alias.
The alias quietly creates and migrates test databases without having a separate test-setup step:
def aliases do [ ... test: [ "ecto.create -r R1 --quiet", "ecto.create -r R2 --quiet", "ecto.migrate -r R1 --quiet", "test" ] ] end
So, when we run
mix test, we do the following:
- create the databases if they don’t exist,
- migrate R1’s data, and
- run the tests
Perfect! We no longer need a separate test-setup step. We can just run our tests
mix test, and the alias will take care of creating databases and
migrating data. ✅
Even more aliases
There’s a lot more you can do with mix aliases. For example, in other projects, I’ve defined an alias to watch assets and prepare them for deployment:
defp aliases do [ ... "assets.deploy": [ "tailwind default --minify", "esbuild default --minify", "phx.digest" ], "assets.watch": ["esbuild default --sourcemap=inline --watch"] ] end
The more I can consolidate within
mix, the better I like it.
So give mix aliases a try. And let me know what useful aliases you create. I’d love to incorporate those into my own projects! 😁