Reading — step 1 of 7
Learn
Mix is Elixir's build tool — like cargo for Rust, npm for Node, gradle for Java. It scaffolds projects, manages dependencies, runs tests, builds releases. Programming Elixir treats Mix as essential. Real Elixir code lives in Mix projects.
Note: Judge0 runs Elixir scripts directly without Mix. This lesson is conceptual — the syntax and patterns below would run inside a Mix project.
Creating a project
mix new my_app
cd my_app
This creates:
my_app/
├── lib/
│ └── my_app.ex # main module
├── test/
│ ├── test_helper.exs
│ └── my_app_test.exs
├── mix.exs # project configuration
├── .formatter.exs
└── README.md
mix.exs — the project file
defmodule MyApp.MixProject do
use Mix.Project
def project do
[
app: :my_app,
version: "0.1.0",
elixir: "~> 1.14",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end
def application do
[
extra_applications: [:logger],
mod: {MyApp.Application, []} # supervision tree starter
]
end
defp deps do
[
{:phoenix, "~> 1.7"},
{:ecto_sql, "~> 3.10"},
{:postgrex, "~> 0.17"},
{:credo, "~> 1.7", only: [:dev], runtime: false}
]
end
end
Three key sections:
project— name, version, deps sourceapplication— runtime config;modpoints to the supervision tree rootdeps— Hex package dependencies (Hex is Elixir's package registry)
Common mix commands
mix deps.get # fetch dependencies
mix compile # compile sources
mix test # run tests
mix run -e "MyApp.do_thing()"
mix iex -S mix # IEx shell with project loaded
mix release # build production release
mix phx.server # for Phoenix apps
Configuration — config/
# config/config.exs
import Config
config :my_app,
api_url: "https://api.example.com",
pool_size: 10
import_config "#{config_env()}.exs"
# config/dev.exs
import Config
config :my_app, debug: true
# config/runtime.exs (loaded at runtime, can use env vars)
import Config
database_url = System.fetch_env!("DATABASE_URL")
config :my_app, MyApp.Repo, url: database_url
Code reads config:
Application.fetch_env!(:my_app, :api_url)
Application.get_env(:my_app, :pool_size, 5)
Application module
For stateful apps, define a supervision tree root:
defmodule MyApp.Application do
use Application
@impl true
def start(_type, _args) do
children = [
MyApp.Repo,
{Phoenix.PubSub, name: MyApp.PubSub},
MyAppWeb.Endpoint
]
opts = [strategy: :one_for_one, name: MyApp.Supervisor]
Supervisor.start_link(children, opts)
end
end
When the BEAM starts, this start/2 callback runs and starts all the supervised children. On crashes, supervision restarts them. The classic OTP pattern.
Hex — Elixir's package registry
mix hex.search phoenix # search packages
mix hex.info ecto # info about a package
mix hex.outdated # check for newer deps
Deps go in mix.exs. After editing, mix deps.get fetches them. Like Cargo.toml + crates.io for Rust.
Releases — production deployment
MIX_ENV=prod mix release
Produces a self-contained tarball with the BEAM, your code, and deps. No runtime requirements on the server. Run with:
_build/prod/rel/my_app/bin/my_app start
Production Elixir deployments are usually releases.
Common mistakes
- Hardcoding configuration in code — use config files; use runtime.exs for env-var-driven values.
- Forgetting
mix deps.getafter editing mix.exs — deps don't auto-fetch; new code won't compile. - Mixing dev/prod config — config/config.exs is for shared, config/{dev,prod,test}.exs for env-specific.
- Putting GenServer.start_link in random places — supervised children belong in the application's supervision tree, not started ad-hoc.
- Skipping tests — Mix's test integration is excellent. Use it from day one.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…