Elixir: Foundations
Why Elixir Exists
Elixir was created by José Valim in 2011–2012 with a specific observation behind it: the Erlang platform
had solved the hardest problems in server software — concurrency, distribution, and fault tolerance —
decades before anyone else, but its syntax and tooling felt alien to programmers raised on mainstream
languages. Elixir keeps the runtime and swaps the surface: a Ruby-inspired syntax, a modern standard
library, a build tool (mix), a package registry (hex), and first-class
documentation tooling (ExDoc).
Three design commitments follow from that history, and every chapter of this track builds on them:
- Immutability by default. Data never changes under you; every transformation returns a new value. Whole categories of race conditions and defensive copies disappear.
- Processes, not threads. Concurrency is expressed as thousands of isolated lightweight processes that share nothing and talk only through messages.
- Let it crash. Instead of defensive error handling everywhere, code that hits an unexpected state dies immediately and a supervisor restarts it in a clean state.
What you give up
Honesty about trade-offs is part of learning a language well. Elixir is not the fastest language for raw numeric loops (Rust, C, and even Julia beat it), it is garbage-collected (you do not control memory the way Rust's ownership model does), and its dynamic typing means fewer compile-time guarantees than statically typed languages — although the gradual set-theoretic type system introduced in Elixir 1.18 and expanded since now catches many errors at compile time. The comparison lesson examines these trade-offs in detail.
The BEAM Runtime
The Erlang virtual machine — the Bogdan/Björn's Erlang Abstract Machine, or BEAM — is the real foundation of every Elixir program. It was designed at Ericsson in the 1980s to run telephone switches that could never go down, and that goal shaped every layer:
- Preemptive scheduling. Each process gets a small budget of reductions (roughly function calls). A tight loop cannot starve other processes — the scheduler preempts it. There is no async/await split: every function is written synchronously.
- Isolated heaps. Every process owns its memory and is garbage-collected individually, so a GC pause in one process never freezes another. Heaps are tiny (a few KB) and collected in microseconds.
- Message passing. Processes share no state. Data sent between processes is copied (except large binaries, which are reference-counted on a shared heap).
- Distribution. Two BEAM nodes that share a cookie form a cluster and can message each other transparently — distribution is a language-level feature, not a library you bolt on.
A first process
This is a complete, runnable Elixir script. It spawns a process, sends it a message, and prints the reply. Do not worry about every keyword yet — the point is that concurrency fits in twelve readable lines with no locks, no thread pool, and no callback pyramid.
# counter.exs — run with: elixir counter.exs
defmodule Counter do
# A process loops forever, waiting for one message at a time.
def loop(count) do
receive do
# A synchronous request: the caller includes its own pid (`self()`).
{:increment, caller} ->
send(caller, {:ok, count + 1})
loop(count + 1) # tail-call: keeps the process alive
end
end
end
pid = spawn(Counter, :loop, [0]) # start with count = 0
send(pid, {:increment, self()}) # self() is this process's pid
receive do # wait for the reply
{:ok, new_count} -> IO.puts("Count is now #{new_count}")
end
Where Elixir Runs Today
Elixir is a production language with public, documented deployments at serious scale. These case studies (from the official case-study page) are worth reading once you finish phase 4:
| Product | What Elixir does there | Why the BEAM fits |
|---|---|---|
| Discord | Real-time messaging fan-out across millions of concurrent users | Millions of lightweight processes map naturally onto millions of connections |
| Supabase Realtime | WebSocket broadcast, presence, and Postgres change streams | Long-lived connections plus fan-out are the BEAM's home turf |
| Plausible Analytics | The entire analytics stack, cookie-free and self-hostable | Small team, high throughput, boring operations |
| Remote | Global employment platform, one Elixir monolith, ~300 engineers | Contexts and process boundaries scale with the org chart |
| BBC | Web infrastructure serving most of its traffic | Traffic spikes handled with graceful degradation |
| Firezone | Open-source remote-access platform (Elixir + WireGuard) | Connection management and policy checks per client |
How the Track Is Organized
The track moves through seven phases. Each phase assumes the previous one; each lesson ends with practice tasks and links to runnable demos in the Lab Examples page.
| Phase | Contents | After it you can… |
|---|---|---|
| 1. Foundations | Overview, comparison with Python/Rust, toolchain, syntax | Run Elixir programs and explain when to choose it |
| 2. Language Core | Data, pattern matching, functions, collections, polymorphism, errors, binaries | Write idiomatic Elixir for everyday logic |
| 3. Metaprogramming & Tooling | Macros, Mix projects, testing, IEx and static analysis | Ship and maintain a real codebase |
| 4. Concurrency & OTP | Processes, tasks, GenServer, supervision, applications, distribution | Design fault-tolerant concurrent systems |
| 5. Production & Ecosystem | Ecto, Phoenix, LiveView, architecture, performance, numerical work | Build and operate production services |
| 6. Practice & Demos | 36 single-file demos, study projects, open-source reading list | Consolidate everything by reading and modifying real code |
| 7. Reference | Verified docs, tutorials, and community links | Keep learning after the track ends |
Practice
- Run the counter script above (it only needs Elixir installed — see Install & Toolchain), then change it so the process also answers
:getmessages with the current count. - Explain in two sentences why a GC pause in one BEAM process cannot freeze another.
- Pick one case study from the table and name the property of the BEAM it depends on most.
- Skim the comparison lesson and write down one thing Elixir does that Python cannot do without extra machinery.
Next: Elixir vs Python vs Rust