HomeProjectsAI FilesBlog

© 2026 Matheus Pires. All rights reserved.

Back to blog

Understanding Elixir and Phoenix for TypeScript developers

April 30, 2026

Why Look at Elixir?

As a TypeScript developer, I spent years in the Node.js ecosystem. But after encountering scaling limitations in real-time applications — WebSocket connections, concurrent data streams, long-running processes — I started exploring BEAM-based languages.

Elixir runs on the Erlang VM (BEAM), which was designed by Ericsson for telecom systems that need to handle millions of concurrent connections with near-zero downtime. The programming model is fundamentally different from what we're used to in TypeScript.

Key Differences

Concurrency Model

TypeScript/Node.js has a single-threaded event loop. Elixir uses the Actor model — each "process" is lightweight, isolated, and runs concurrently:

# Spawn 10,000 concurrent processes — no thread pool needed
for i <- 1..10_000 do
  spawn(fn -> do_work(i) end)
end

In Node.js, 10,000 concurrent operations would block the event loop or require worker threads. In Elixir, each process is scheduled independently across CPU cores.

Immutable Data Structures

Everything in Elixir is immutable by default. No const vs let — you simply can't mutate data:

list = [1, 2, 3]
new_list = [0 | list]  # creates a new list, doesn't modify original
# list is still [1, 2, 3]

This eliminates a whole class of bugs related to shared mutable state.

Pattern Matching

Instead of if/else, Elixir leans heavily on pattern matching:

def process({:ok, user}) do
  handle_success(user)
end

def process({:error, reason}) do
  handle_error(reason)
end

This reads like TypeScript discriminated unions, but it's the default control flow mechanism, not an optional pattern.

No Classes

Elixir uses modules and functions instead of classes. No this, no inheritance hierarchies, no super():

defmodule User do
  def greet(%{name: name}) do
    "Hello, #{name}"
  end
end

Phoenix: The Rails of Elixir

Phoenix is the web framework for Elixir, and it's excellent. Some highlights:

  • LiveView — build real-time interactive applications without writing JavaScript
  • PubSub — built-in publish/subscribe for real-time features
  • Channels — WebSocket connections as a first-class citizen

What Feels Familiar

If you're coming from TypeScript, some things translate directly:

TypeScriptElixir
type Result<T, E> = { ok: true, value: T } | { ok: false, error: E }{:ok, value} / {:error, reason}
pipe()`
map() / filter()Enum.map() / Enum.filter()
async/awaitTask.async() / Task.await()

The concept of tagged unions in TypeScript maps almost perfectly to Elixir's tuple-based result handling.

Should You Learn It?

If you're building real-time systems, distributed applications, or anything that needs to handle high concurrency gracefully — yes. The learning curve is real, but the mental model shift is valuable even if you don't use Elixir full-time.

Understanding the Actor model and immutable-by-default programming will change how you think about system design, regardless of the language you write in.