Elixir is a functional programming language built on the Erlang virtual machine. It is designed for building reliable, concurrent systems — and has a friendly, readable syntax.
Getting Started
# Install via https://elixir-lang.org/install.html
elixir --version
# Start an interactive shell
iex
# Run a script
elixir my_script.exs
# Create a new project
mix new my_app
cd my_app
mix runBasic Types
42 # integer
3.14 # float
true # boolean
:ok # atom (like a symbol — often used as a label)
"hello" # string
'hello' # charlist (rarely used directly)
nil # represents absence of a valueAtoms are constants whose name is their value. :ok and :error are common atoms you'll see in Elixir code.
Variables
Variables are bound with =. In Elixir, = is the match operator, not just assignment.
name = "Alice"
age = 30
sum = 1 + 2 # => 3Variables are immutable — you can rebind a name, but the original value never changes.
Strings
Strings are UTF-8 encoded. Use "double quotes" for strings.
greeting = "Hello"
name = "world"
"#{greeting}, #{name}!" # => "Hello, world!" (string interpolation)
String.length("hello") # => 5
String.upcase("hello") # => "HELLO"
String.split("a,b,c", ",") # => ["a", "b", "c"]Lists
Lists are ordered collections that can hold any type. They are implemented as linked lists.
fruits = ["apple", "banana", "cherry"]
hd(fruits) # => "apple" (head — first element)
tl(fruits) # => ["banana", "cherry"] (tail — rest of the list)
length(fruits) # => 3
["mango" | fruits] # => ["mango", "apple", "banana", "cherry"]Concatenate or subtract lists:
[1, 2, 3] ++ [4, 5] # => [1, 2, 3, 4, 5]
[1, 2, 3, 2] -- [2] # => [1, 3, 2]Tuples
Tuples are fixed-size collections, stored contiguously in memory. Good for grouping a known number of values.
{:ok, "Alice", 30}
point = {10, 20}
{x, y} = point # pattern match to extract values
x # => 10
y # => 20A common Elixir convention is to return {:ok, value} on success and {:error, reason} on failure.
Maps
Maps store key-value pairs. Keys can be any type, but atoms are most common.
user = %{name: "Alice", age: 30, role: "admin"}
user.name # => "Alice"
user[:role] # => "admin"
Map.get(user, :age) # => 30Update a map (returns a new map — the original is unchanged):
updated = %{user | age: 31}
updated.age # => 31
user.age # => 30 (original untouched)Pattern Matching
Pattern matching is one of Elixir's most powerful features. The = operator matches the left side against the right side.
{status, value} = {:ok, 42}
status # => :ok
value # => 42
[first | rest] = [1, 2, 3]
first # => 1
rest # => [2, 3]Use _ to ignore a value you don't need:
{_, value} = {:ok, "hello"}
value # => "hello"Functions
Anonymous functions are created with fn ... end and called with .():
double = fn x -> x * 2 end
double.(5) # => 10
add = fn a, b -> a + b end
add.(3, 4) # => 7The & shorthand creates compact anonymous functions:
double = &(&1 * 2)
double.(5) # => 10
add = &(&1 + &2)
add.(3, 4) # => 7Modules and Named Functions
Group related functions inside a defmodule block. Use def for public functions and defp for private ones.
defmodule Greeter do
def hello(name) do
"Hello, #{name}!"
end
defp shout(text) do
String.upcase(text)
end
end
Greeter.hello("Alice") # => "Hello, Alice!"Multiple Function Clauses
Elixir matches function clauses top to bottom. Write multiple clauses to handle different inputs.
defmodule Math do
def factorial(0), do: 1
def factorial(n), do: n * factorial(n - 1)
end
Math.factorial(5) # => 120Control Flow — if and unless
if age >= 18 do
"adult"
else
"minor"
end
unless logged_in do
"please log in"
endControl Flow — case
case matches a value against multiple patterns:
case File.read("data.txt") do
{:ok, contents} ->
IO.puts("File contents: #{contents}")
{:error, :enoent} ->
IO.puts("File not found")
{:error, reason} ->
IO.puts("Error: #{reason}")
endControl Flow — cond
cond evaluates conditions in order and runs the first truthy one:
cond do
score >= 90 -> "A"
score >= 80 -> "B"
score >= 70 -> "C"
true -> "F" # default — like else
endThe Pipe Operator
|> passes the result of one expression as the first argument of the next. It makes chained operations easy to read.
Without pipe:
String.downcase(String.trim(" Hello World "))
# => "hello world"With pipe:
" Hello World "
|> String.trim()
|> String.downcase()
# => "hello world"Enum
The Enum module provides functions for working with lists and other collections.
numbers = [1, 2, 3, 4, 5]
Enum.map(numbers, fn n -> n * 2 end) # => [2, 4, 6, 8, 10]
Enum.filter(numbers, fn n -> n > 3 end) # => [4, 5]
Enum.reduce(numbers, 0, fn n, acc -> acc + n end) # => 15
Enum.sum(numbers) # => 15
Enum.max(numbers) # => 5With the pipe operator:
[1, 2, 3, 4, 5]
|> Enum.filter(&(&1 > 2))
|> Enum.map(&(&1 * 10))
# => [30, 40, 50]Mix — Build Tool
Mix is Elixir's built-in build tool. It handles dependencies, compilation, and running code.
mix new my_app # create a new project
mix compile # compile the project
mix run # run the project
mix test # run tests
mix deps.get # install dependencies
iex -S mix # open iex with the project loadedDependencies go in mix.exs:
defp deps do
[
{:httpoison, "~> 2.0"},
{:jason, "~> 1.4"}
]
end