Erlang is the language the BEAM was written in. Elixir adds friendlier syntax on top of the same machine, but this site’s Erlang Introduction teaches Erlang straight from JS. The atoms, tuples, immutability, and pattern matching are the same ideas you already use, spelled differently. This cheat sheet maps the JS you know onto the Erlang you are about to read. It is aimed at the Erlang Introduction course and pairs with Reading Elixir as a JS developer and Reading Lua as a JS developer.
The core mapping
| JS | Erlang | Notes |
|---|---|---|
function f(x) { ... } |
f(X) -> ... . |
A -module + -export header replaces the file; each clause ends in .. |
let / const x = 5 |
X = 5 |
Variables are Uppercase; lowercase names are atoms. Single-assignment: rebinding is an error. |
true / false |
true / false |
Same atoms, no change. |
| (no JS equivalent) |
ok, square, error |
Atoms are bare lowercase words — Erlang’s symbol/enum. |
| (no JS equivalent) |
{A, B} |
Tuples: fixed-size, heterogeneous — Erlang’s “lightweight object”. |
[1, 2, 3] |
[1, 2, 3] |
Arrays are lists; [H | T] splits head and tail. |
a === b / a !== b |
A =:= B / A =/= B |
Strict equality. (Beware: Erlang’s == is not strict.) |
a && b, a || b, !a |
A and B, A or B, not A |
Boolean operators are words. |
if (x) { ... } else { ... } |
case X of ... end |
if and switch both become case; add a when guard for conditions. |
x ? y : z |
case ... of ... end |
The ternary is a two-clause case. |
{a: 1} |
#{a => 1} |
Objects are maps, spelled => not :. |
obj.a |
maps:get(a, Obj) |
Property access goes through the maps: module. |
x => x * 2 |
fun(X) -> X * 2 end |
Arrow functions spell fun and end with end. |
"hello" (string) |
<<"hello">> |
"hello" is a list of integers; binaries use <<...>>. |
for (const x of xs) { ... } |
[Expr || X <- Xs] |
List comprehensions, different spelling. |
xs.map(x => ...) |
lists:map(fun(X) -> ... end, Xs) |
map lives in the lists: module. |
xs.reduce((acc, x) => ..., 0) |
lists:foldl(fun(X, Acc) -> ... end, 0, Xs) |
Same shape, spelled out. |
The rule is simple: Erlang keeps the ideas and removes the sugar. The function and => ceremony becomes -module/-export plus -> clauses. let and const become Uppercase names. The { } blocks become -> ... . clauses.
The one habit that trips you up: . and ; and ,
JS uses { } to group statements, so punctuation barely matters. Erlang has no braces. Three characters do that work instead, and confusing them is the classic first-hour bug:
area({square, Side}) -> Side * Side;
area({circle, Radius}) -> 3.14 * Radius * Radius.
Read from left to right. , separates expressions within a clause, ; separates clauses of the same function, and . ends the last clause. A missing . on the final clause, or a . where a ; belongs, is a syntax error. There is no closing } nearby to show you the problem; the compiler simply says the module is malformed. Count the clauses. Exactly one must end in ..
The other big difference: strings are lists
This is the genuinely alien part. In JS, "hello" is a string. In Erlang, "hello" is shorthand for the list of integers [104, 101, 108, 108, 111] — one element per character’s code point, a legacy of the 1980s. The modern string type is a binary, written with different brackets: <<"hello">>.
That is why the Erlang Introduction teaches atoms and tuples instead of strings, and why the string-handling exercises elsewhere on the site use the other languages. In Erlang, "text" is a list of numbers. If you want a string, you almost always mean <<"text">>.
No loops: recursion is the loop
Erlang has no for, no while, and no array methods. Repetition means recursion: a function calls itself with a base case. The standard library’s lists: module replaces the array methods. JS writes xs.map(x => x * 2); Erlang writes lists:map(fun(X) -> X * 2 end, Xs). JS writes xs.reduce((acc, x) => acc + x, 0); Erlang writes lists:foldl(fun(X, Acc) -> X + Acc end, 0, Xs). The shape is the same, but Erlang spells it out and uses a fun instead of an arrow.
The runner contract
The site grades Erlang the same way it grades every language: write a module named solution, export the function the check names, and let the grader call it with hidden inputs. Erlang adds two header lines and the . terminators:
-module(solution).
-export([compute/2]).
compute(A, B) -> (A + B) * (A - B).
compute/2 means “the function compute taking 2 arguments.” It must appear in the -export list or the grader cannot see it. Every function the check grades uses this form; the lessons cover the rest.
Where to go next
- Erlang Introduction - the eleven-lesson course: one idea at a time, each check graded by the real runner.
- Reading Elixir as a JS developer - the friendlier syntax on top of the same machine; the two cheat sheets read best side by side.
- What the BEAM actually is - the machine both languages run on, in five minutes.
Erlang is the machine with the training wheels off: the same atoms, the same tuples, the same immutability — just Uppercase variables, . terminators, and no { } blocks to hide the structure.