My Journey into Elixir/Erlang (Part One)
Recently, I started diving into the world of Elixir and Erlang/OTP. If, like me, you thought these technologies were just "hipster stuff," this post might change your mind. Why Did I Start Learning It? I had heard about Elixir before. It occasionally popped up in my feed, but without much impact. It just seemed like another "hipster" language to me. The turning point came when our tech director at work (shoutout to Dima if you're reading this) launched a full scale campaign promoting the language. He gave such an inspiring speech that I was ready to storm Berlin a second time. A Bit of Context Before this, I had been writing servers in go, php, and nodejs. I had a solid understanding of concurrency and how to write parallel code. In go, I had goroutines; in nodejs, threads/libuv; and in php... well, either the nightmare of pthreads or the newer fibers, which made things a bit better. It all worked fine, this was how people wrote concurrent code, and that was that. And then BEAM (the virtual machine that runs Elixir/Erlang code) kicked down the door and shattered everything I thought I knew about concurrency. This isn’t some shabby setup like on the JVM; (sorry, i'm jvm hater). I started getting excited about Elixir. Flashbacks hit me of all the things I could have done better in my past projects. It was a night-and-day difference, and I regretted not jumping into this ecosystem sooner. Learning Curve It's true that there aren't as many learning resources compared to the languages I was used to, and the community is much smaller. But honestly, that wasn’t a big issue for me. Elixir has excellent documentation, well structured and clear, so that’s where I started. The syntax was easy to pick up. My muscle memory kicked in since I had played around with Ruby years ago (purely for Rails). Getting used to it wasn't hard, and the reward was massive the joy of pattern matching alone made it worth it. Of course, this is just my personal experience; your mileage may vary. I started by writing small scripts, and my colleagues at work threw some Elixir tasks my way. My hands quickly got used to it. Of course, I understood the power of Elixir; as I mentioned earlier, I was swayed by a powerful speech about BEAM and Elixir. When I finally got to Erlang/OTP and really explored BEAM, that's when things got truly exciting. Where Are the Threads? I asked myself... just kidding. That’s not how things work here. Out of habit, I Googled "Elixir threads," looking for something like spawn_thread() or async do. But in Elixir, things are built differently. Elixir doesn’t have threads in the traditional sense. Everything here is based on processes (hello, Actor Model). Processes These aren’t OS processes, they're super lightweight and run inside BEAM. They don’t share memory, don’t block each other, and operate independently. You can spawn hundreds of thousands of processes at the same time hell, even a million (and I’m not just throwing around big numbers; we’ll come back to that). More importantly, they use very little memory and switch context in milliseconds. What If a Process Crashes? Now, this is where things get interesting. Elixir has a completely different philosophy: no recover(), no try/catch. If something goes wrong? Let it crash! (Yes, "let it crash" is an actual design principle.) To understand how cool this is, imagine this: You spin up an HTTP server in Node.js, and it crashes because of an error in a single request. Instead of a full system crash, it just restarts itself without your intervention. Or imagine a worker goroutine in Go dies, but the system automatically brings it back to life. Sounds good? Well, in Elixir, you don’t have to imagine it, it’s built-in by default. The entire architecture is designed around BEAM and supervisors, which restart crashed processes automatically. You don’t need to do much just trust BEAM. I feel like someone who spent their whole life tightening screws by hand, and then someone handed me a power drill. Joking aside, I’m not saying Node.js or Go is bad, it’s just that Elixir plays by completely different rules, and I love it. About BEAM Why does all this work so amazingly well? Because Elixir runs on BEAM (the virtual machine), which was originally developed for telecommunications (hi, Erlang). Back when people had to worry about: Avoiding thread-related disasters Handling failures Preventing memory leaks In Elixir, you just trust BEAM. This VM comes from the telecom world, where downtime means lost revenue. It does things I could only dream of in Go/Node/PHP. Imagine your code isn’t running as one big process but as millions of tiny processes, each living its own life. If one crashes, who cares? The others won’t even notice. If the load increases, BEAM automatically distributes tasks across CPU cores. If memory gets cluttered, the garbage collector cleans it up without sto

Recently, I started diving into the world of Elixir and Erlang/OTP. If, like me, you thought these technologies were just "hipster stuff," this post might change your mind.
Why Did I Start Learning It?
I had heard about Elixir before. It occasionally popped up in my feed, but without much impact. It just seemed like another "hipster" language to me.
The turning point came when our tech director at work (shoutout to Dima if you're reading this) launched a full scale campaign promoting the language. He gave such an inspiring speech that I was ready to storm Berlin a second time.
A Bit of Context
Before this, I had been writing servers in go, php, and nodejs. I had a solid understanding of concurrency and how to write parallel code. In go, I had goroutines; in nodejs, threads/libuv; and in php... well, either the nightmare of pthreads or the newer fibers, which made things a bit better. It all worked fine, this was how people wrote concurrent code, and that was that.
And then BEAM (the virtual machine that runs Elixir/Erlang code) kicked down the door and shattered everything I thought I knew about concurrency. This isn’t some shabby setup like on the JVM; (sorry, i'm jvm hater).
I started getting excited about Elixir. Flashbacks hit me of all the things I could have done better in my past projects. It was a night-and-day difference, and I regretted not jumping into this ecosystem sooner.
Learning Curve
It's true that there aren't as many learning resources compared to the languages I was used to, and the community is much smaller. But honestly, that wasn’t a big issue for me. Elixir has excellent documentation, well structured and clear, so that’s where I started.
The syntax was easy to pick up. My muscle memory kicked in since I had played around with Ruby years ago (purely for Rails). Getting used to it wasn't hard, and the reward was massive the joy of pattern matching alone made it worth it. Of course, this is just my personal experience; your mileage may vary.
I started by writing small scripts, and my colleagues at work threw some Elixir tasks my way. My hands quickly got used to it. Of course, I understood the power of Elixir; as I mentioned earlier, I was swayed by a powerful speech about BEAM and Elixir.
When I finally got to Erlang/OTP and really explored BEAM, that's when things got truly exciting.
Where Are the Threads?
I asked myself... just kidding. That’s not how things work here. Out of habit, I Googled "Elixir threads," looking for something like spawn_thread() or async do. But in Elixir, things are built differently.
Elixir doesn’t have threads in the traditional sense. Everything here is based on processes (hello, Actor Model).
Processes
These aren’t OS processes, they're super lightweight and run inside BEAM. They don’t share memory, don’t block each other, and operate independently.
You can spawn hundreds of thousands of processes at the same time hell, even a million (and I’m not just throwing around big numbers; we’ll come back to that). More importantly, they use very little memory and switch context in milliseconds.
What If a Process Crashes?
Now, this is where things get interesting. Elixir has a completely different philosophy: no recover(), no try/catch. If something goes wrong? Let it crash! (Yes, "let it crash" is an actual design principle.)
To understand how cool this is, imagine this:
You spin up an HTTP server in Node.js, and it crashes because of an error in a single request. Instead of a full system crash, it just restarts itself without your intervention. Or imagine a worker goroutine in Go dies, but the system automatically brings it back to life.
Sounds good? Well, in Elixir, you don’t have to imagine it, it’s built-in by default. The entire architecture is designed around BEAM and supervisors, which restart crashed processes automatically. You don’t need to do much just trust BEAM.
I feel like someone who spent their whole life tightening screws by hand, and then someone handed me a power drill. Joking aside, I’m not saying Node.js or Go is bad, it’s just that Elixir plays by completely different rules, and I love it.
About BEAM
Why does all this work so amazingly well? Because Elixir runs on BEAM (the virtual machine), which was originally developed for telecommunications (hi, Erlang).
Back when people had to worry about:
- Avoiding thread-related disasters
- Handling failures
- Preventing memory leaks
In Elixir, you just trust BEAM. This VM comes from the telecom world, where downtime means lost revenue. It does things I could only dream of in Go/Node/PHP.
Imagine your code isn’t running as one big process but as millions of tiny processes, each living its own life. If one crashes, who cares? The others won’t even notice. If the load increases, BEAM automatically distributes tasks across CPU cores. If memory gets cluttered, the garbage collector cleans it up without stopping your app.
In other languages, you need complex frameworks, message brokers, and DevOps wizardry to achieve this. In Elixir, it’s just part of the platform.
Where else can you hot-swap code in a running application without stopping or restarting it? While handling thousands of concurrent requests? That’s BEAM for you.
One Million Processes
Here’s a simple example, let’s spawn some processes:
spawn(fn -> IO.puts("My name is Jeff") end)
spawn(fn -> IO.puts("JVM started with 8GB RAM") end)
And it’s not just a neat syntax trick. As I said before, these processes don’t share memory, don’t block each other, no mutexes, no race conditions.
You can spawn hundreds of thousands, even a million:
for _ <- 1..1_000_000, do: spawn(fn -> receive do _ -> :ok end end)
My m1 macbook air didn’t even break a sweat...
A better example:
defmodule MyWorker do
use GenServer
def init(_), do: {:ok, %{count: 0}}
def handle_call(:fail, _, _), do: raise("I crashed")
end
Supervisor.start_link([{MyWorker, []}], strategy: :one_for_one)
Process crashed? It gets restarted. Crashed a million times? It gets restarted a million times.
In other languages, you’d need a whole DevOps setup with monitoring, restart policies, and tools like systemd or Docker restart strategies to achieve this.
Is It Worth Learning?
Yes.
P.S. That’s the shortest H2 title in the Wild West.
What’s Next?
There will be a part two, about distributed systems and more on OTP. I’m still new to all of this, but there’s a lot of cool stuff I want to write about.