What the BEAM actually is, in 5 minutes

LLM-authored, human-reviewed

Foundations Concurrency & the BEAM

You’ll see “the BEAM” around Elixir constantly, usually without an explanation. This article gives you one: where the BEAM came from, the idea behind its design, what that design costs, and where it appears in the work you practice here. It draws on Elixir in Action, Erlang and OTP in Action, and Programming Erlang. The BEAM is old and unusual, so use the sources instead of a rumor.

Elixir is not the BEAM

Elixir is a language. The BEAM is the virtual machine that runs it. The name is an acronym - Bogdan/Björn’s Erlang Abstract Machine, after the engineers who built it. Ericsson built it for Erlang and telephone switches. The reference text states the origin and the constraint in one sentence: “Conceived in the mid-1980s by Ericsson, a Swedish telecom giant, Erlang was driven by the needs of the company’s own telecom systems, where properties like reliability, responsiveness, scalability, and constant availability were imperative. A telephone network should always operate regardless of the number of simultaneous calls, unexpected bugs, or hardware and software upgrades taking place.”

That last clause is the specification. A telephone switch cannot stop to restart. Calls in progress must survive an upgrade. One failing component must not take down the exchange. The language and the VM were designed so that the system keeps operating, not just one program. Elixir compiles to the same bytecode as Erlang and runs on the same VM. That makes “the BEAM ecosystem” real: any language that targets this VM (Erlang, Elixir, Gleam, LFE) gets its guarantees and tooling, and BEAM libraries and BEAM processes interoperate regardless of which language created them. The reference is careful to note that telecom did not limit the tool: “Despite being originally built for telecom systems, Erlang is in no way specialized for this domain. It doesn’t contain explicit support for programming telephones, switches, or other telecom devices. Instead, Erlang is a general-purpose development platform that provides special support for technical, nonfunctional challenges, such as concurrency, scalability, fault tolerance, distribution, and high availability.”

The one idea that explains almost everything else

The BEAM’s model fits in one sentence. Every guarantee in this article follows from it. The reference states it directly:

The basic concurrency primitive is called an Erlang process (not to be confused with OS processes or threads), and typical Erlang systems run thousands, or even millions, of such processes.

A JavaScript program is (usually) one thread doing one thing and sharing memory with everything else in the process. A BEAM program is thousands to millions of processes. Each has its own memory and communicates with the others only by sending messages. These are not the OS processes or threads you are picturing: “BEAM processes are much lighter and cheaper than OS processes.” They are green threads scheduled by the VM itself. Spawning a hundred thousand is normal, and the VM’s schedulers distribute them over the CPU cores: “The Erlang virtual machine uses its own schedulers to distribute the execution of processes over the available CPU cores, thus parallelizing execution as much as possible.”

The machinery under that sentence is worth naming. Each piece buys a different guarantee:

  • A process is a sequential program plus a mailbox. “Sending a message amounts to storing it into the receiver’s mailbox. The caller then continues with its own execution, and the receiver can pull the message in at any time and process it in some way.” The mailbox is described as “a FIFO queue limited only by the available memory.” There is no shared state to lock, because there is no shared state at all.
  • Messages are copies. “Because processes can’t share memory, a message is deep copied when it’s sent.” The sender and receiver never touch the same bytes - which is why nothing one process does to its data can corrupt another process’s view of anything.
  • The scheduler is preemptive. “A scheduler is preemptive - it gives a small execution window to each process and then pauses it and runs another process. Because the execution window is small, a single long-running process can’t block the rest of the system.” An infinite loop in one process costs that process its turns, not the system its responsiveness.
  • Garbage collection is per-process. “Processes are completely isolated and share no memory. This allows per-process garbage collection; instead of stopping the entire system, each process is individually collected, as needed.” A stop-the-world pause is impossible by construction.
  • The schedulers steal work. On a multicore machine the schedulers do not blindly partition the processes; the OTP reference describes the balancing: “processes can be moved from one pool to another to maintain an even balance of work over the available schedulers.”

One scheduler, three processes: one runs while the others wait, and each
keeps its own mailbox - the whole concurrency model in a single picture.

These are all the same idea: isolation first. No shared memory, no shared locks, no shared garbage collector, and no shared scheduler queue that one bad process can wedge. The model spends its design budget on preventing one process from stopping the others. That is what a telephone switch requires.

Why a crash is cheap: isolation and the dying shout

The famous consequence follows from isolation. The reference says:

Erlang processes are completely isolated from each other. They share no memory, and a crash of one process doesn’t cause a crash of other processes. This helps you isolate the effect of an unexpected error. If something bad happens, it has only a local effect. Moreover, Erlang provides you with the means to detect a process crash and do something about it; typically, you start a new process in place of the crashed one.

A crash belongs to one process. The rest of the system learns about it only when another process is told. The “means to detect” is the supervisor: a process whose job is watching another process and restarting it. The let-it-crash article covers that in full. Restarting beats recovery because the dying process says why it died. The language’s creator put it in his characteristic register: “Erlang processes are just like people - they can on occasion die. Unlike people, when they die, they shout out in their last breath exactly what they have died from.” The crashed process reports the cause, and the supervisor can restart it without understanding that cause.

That is the key difference from the shared-memory world. In JavaScript, an uncaught exception in a callback can leave a promise chain dangling or an event loop wedged. In a shared-memory language, one bad write can corrupt whatever shares the address space. The BEAM makes the opposite bet: the unit of failure is the process, the unit of recovery is the restart, and neither touches anything outside its own mailbox. Armstrong’s framing of the whole enterprise is worth taking seriously - the reference opens by describing the goal as “programming a distributed concurrent system without locks and mutexes but using only pure message passing.”

What the model costs

Isolation is not free. The BEAM’s price is no shared memory means every message is a copy. The “deep copied when it’s sent” semantics make the model safe, but they also impose a tax: a large term sent to another process is physically duplicated. The site’s own stored-program article explains why copying is the only honest way to share. In practice, the tax is smaller than it sounds because the VM is “optimized for the efficient input, output, and message passing of binaries,” and immutable data means the copy is the only way two processes can ever disagree. It is still real. A model that needs no locks pays for every crossing of a process boundary.

The second cost is conceptual. A BEAM program is not one computation; it is a population. “Concurrency-oriented programming,” as the reference calls it, means modeling the problem as a set of interacting processes rather than a single flow. That is a real shift for a programmer raised on one-thread-at-a-time. It is also the point: concurrency is not a performance mode you opt into. It is the model the whole language is built on.

Where this shows up in what you’re practicing here

You will spawn processes and pass messages on this site. The Process Ring, Ping-Pong Counter, Print in Order (concurrent), and Dining Philosophers exercises all do. OTP supervisors are not required here. The language design choices you are drilling still trace back to this model:

  • Immutability - nothing to corrupt if nothing is ever mutated; a message can be copied safely because the data it carries cannot change under anyone.
  • Pattern matching as control flow - a natural fit for “what kind of message did I just receive?”, which is what a process does all day.
  • Small, composable functions - each one easy to run in isolation, restart, and test, which is the same instinct the process model institutionalizes.

The Process Ring exercise is the model in miniature: a ring of processes passing a token. Print in Order is the ordering question - Kahn’s algorithm, a valid sequence or a cycle. Print in Order (concurrent) is the same question enforced at runtime. Solve those, and the “thousands of isolated processes” claim stops being an assertion about the BEAM. It becomes something you have done.

Go deeper

This article is the map, not the territory. The Elixir community has produced long-form treatments of this topic. Search for “Saša Jurić - The Soul of Erlang and Elixir”, a widely-cited conference talk that walks through the process model and “let it crash” philosophy in full. The official erlang.org site is also worth reading for the BEAM’s own documentation, straight from the source.

Where to go next

  • Process Ring - the BEAM’s message passing as an exercise: spawn a ring of processes, pass a token, and watch the mailbox edges carry it.
  • Ping-Pong Counter - two processes bouncing a counter. The grader watches the messages.
  • Print in Order - the ordering question: given tasks and prerequisites, is a valid order even possible?
  • Print in Order (concurrent) - three processes that must fire in order, coordinated by messages instead of locks.
  • Dining Philosophers - deadlock avoidance as an exercise: n philosophers, n forks, everyone eats.
  • Let it crash - the philosophy this article’s process model exists to serve: crashes are isolated, restarts are the recovery.
  • The BEAM is the broker and Publish-subscribe - what the message passing is actually for: decoupling producers from consumers.
  • Bits have no meaning - the machine the BEAM runs on, and the stored-program bargain underneath the runtime.
  • Graphs: when the answer is a hop away
    • the scheduler’s work-stealing is a graph algorithm; this article names the graph.

The BEAM started with a telephone-switch requirement: survive upgrades, bugs, and hardware failures without stopping. It was then generalized. One idea - thousands of isolated processes that can only exchange copies - explains the scheduler, the garbage collector, crash isolation, and the “let it crash” philosophy. It is the oldest concurrency model in this article, and its unit of failure is still small enough to recover from.

← Back to articles