100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

Erlang Interview Questions

A guided walkthrough of the Erlang concepts interviewers probe most — the actor-model concurrency system, OTP fault tolerance, pattern matching, and distribution — with the reasoning behind each question.

PracticeIntermediate10 min readJul 10, 2026
Analogies

Erlang Interview Questions: What Interviewers Are Really Testing

Erlang interviews rarely stay at the syntax level for long, because the language's real value shows up in how it handles concurrency and failure at scale. Interviewers use questions about processes, OTP behaviours, pattern matching, and distribution as proxies for whether a candidate has actually built and operated a concurrent, fault-tolerant system rather than just read about one. A strong candidate doesn't just recite that 'processes are cheap' or that Erlang 'lets it crash' — they can explain the mechanism behind each claim and connect it to a concrete production scenario, which is exactly what the sections below walk through.

🏏

Cricket analogy: Just as a chief selector doesn't only want a batter who knows the textbook cover drive but one who can explain why they chose it against a specific bowler like Jasprit Bumrah on a seaming pitch, interviewers want the reasoning behind an Erlang answer, not just the memorized term.

Concurrency Model Questions

Erlang's concurrency model is built on the actor model: every process is a lightweight, independently scheduled unit managed entirely by the BEAM virtual machine, not by the operating system. Process creation is cheap — a new process starts with a small heap of only a few hundred words — and each process owns a private, isolated heap, so there is no shared mutable memory and no need for locks or mutexes between processes. Garbage collection happens per-process and never stops the rest of the system, and all communication happens exclusively through asynchronous message passing into a process's mailbox, read via selective receive. The BEAM scheduler (typically one OS thread per core) preemptively switches between processes based on a reduction count — roughly 2000 function calls per process before it must yield — rather than a fixed time slice, which guarantees fairness even under heavy load. Interviewers ask about this because it explains why Erlang systems can run millions of concurrent processes where a thread-per-connection model in most languages runs out of memory or context-switching overhead in the low thousands.

🏏

Cricket analogy: It's like an IPL franchise fielding thousands of net bowlers simultaneously across dozens of practice pitches instead of rotating a handful of expensive specialist bowlers one at a time — each net session is cheap to set up and isolated, so one bowler breaking down doesn't stop the others.

erlang
%% Spawn a lightweight process and communicate via message passing
loop() ->
    receive
        {From, {add, A, B}} ->
            From ! {self(), A + B},
            loop();
        stop ->
            ok
    end.

start_and_call() ->
    Pid = spawn(fun loop/0),
    Pid ! {self(), {add, 2, 3}},
    receive
        {Pid, Result} ->
            io:format("Result: ~p~n", [Result])
    after 5000 ->
        io:format("Timed out waiting for reply~n")
    end.

OTP and Fault Tolerance Questions

"Let it crash" is Erlang's philosophy of not defensively coding against every conceivable failure inside a process, and instead letting a process terminate when it hits an unexpected state, while a supervisor detects that exit and restarts the process into a known-good state. Interviewers ask about this to check whether a candidate understands that supervision trees turn error handling into a structural, declarative concern rather than scattered try/catch blocks: a supervisor is configured with a restart strategy — one_for_one restarts only the failed child, one_for_all restarts every sibling, rest_for_one restarts the failed child plus every child started after it, and simple_one_for_one is used for dynamically spawned children of the same type — along with a restart intensity such as allowing at most 3 restarts within 5 seconds before the supervisor itself gives up and escalates. A strong answer also explains that process links propagate exit signals, and a supervisor traps those exits via process_flag(trap_exit, true) so it can react instead of dying itself, which is the actual mechanism that makes Erlang systems self-healing in production.

🏏

Cricket analogy: It's like a captain not benching a bowler mid-over for one bad delivery but instead relying on the team management structure to review and reset the bowler's role for the next match — the fix happens at the team-management level, not by micromanaging every ball.

A common interview mistake is claiming Erlang processes are just threads under the hood, or that "let it crash" means Erlang has no error handling at all. In reality, BEAM processes are scheduled entirely in user space by the VM with their own isolated heaps, and "let it crash" is a deliberate strategy applied to unexpected states — code still validates input, uses guards, and catches genuinely recoverable errors; it simply avoids defensively handling every conceivable failure inline.

gen_server, gen_statem, gen_event, and Hot Code Reloading

Interviewers frequently ask candidates to distinguish OTP's core behaviours. gen_server implements the generic client/server pattern — call for synchronous request/reply (with a default 5-second timeout), cast for asynchronous fire-and-forget, and handle_info for out-of-band messages — and is the workhorse behind most stateful services. gen_statem, which replaced the older gen_fsm, models a process as an explicit state machine using either state_functions or handle_event_function callback mode, letting each state pattern-match incoming events and transition explicitly, which suits protocols, connection handshakes, or anything with well-defined states. gen_event manages a set of pluggable handler modules that can be added or removed independently at runtime and that all react to events broadcast through one manager process, which is why it's the classic choice for logging or alerting fan-out. Hot code reloading builds on the code server keeping at most two versions of a module resident at once — current and old — and a long-running loop process only picks up the new version when it makes a fully qualified call (Module:Function); OTP behaviours implement the code_change/3 callback specifically to transform their internal State term across an upgrade so in-flight processes don't need to restart, which is what makes zero-downtime releases possible via appup and relup instructions.

🏏

Cricket analogy: gen_server is like a wicketkeeper giving the captain a direct answer, gen_statem is like a bowler's over moving through explicit phases — new ball, middle overs, death overs, and gen_event is like a commentary panel where several commentators all react to the same delivery.

erlang
-module(counter_server).
-behaviour(gen_server).

-export([start_link/0, increment/0]).
-export([init/1, handle_call/3, handle_cast/2, code_change/3]).

start_link() ->
    gen_server:start_link({local, ?MODULE}, ?MODULE, 0, []).

increment() ->
    gen_server:call(?MODULE, increment).

init(Count) ->
    {ok, Count}.

handle_call(increment, _From, Count) ->
    {reply, Count + 1, Count + 1}.

handle_cast(_Msg, State) ->
    {noreply, State}.

%% Invoked automatically during a release upgrade so in-flight
%% state can be transformed to match the new code version.
code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

Pattern Matching and Data Structures Questions

Pattern matching in Erlang is not just destructuring — it's a control-flow mechanism, since function clauses, case, and receive all select a branch by matching a value's shape, including matching against already-bound variables, which is a classic interview trap for candidates coming from imperative languages. Guards (a when clause restricted to guard-safe built-ins like is_integer/1, length/1, or comparison operators) add conditions that can never raise an exception, which distinguishes them from if, which requires one of its own guard-sequence clauses to evaluate true or it errors with no matching clause, and from case, which is the general-purpose form for matching arbitrary patterns and typically includes a catch-all fallback clause. On the data-structure side, interviewers commonly probe the difference between ETS (Erlang Term Storage), an in-memory table that lives outside any single process's heap and can be read from or written to directly by any process without message passing, supporting set, ordered_set, bag, and duplicate_bag semantics; the process dictionary, a mutable key-value store scoped to a single process that is generally discouraged because it breaks referential transparency; and Mnesia, a distributed, transactional database built on top of ETS and DETS that adds replication, disk persistence, and transactions across cluster nodes.

🏏

Cricket analogy: Matching against a bound variable is like DRS only upholding a decision if pitching-in-line, impact-in-line, and hitting-the-stumps all match exactly; ETS is like a shared team scoreboard any player can read or update, while the process dictionary is like one player's personal notebook.

When comparing gen_server:call/2 with gen_server:cast/2 in an interview answer, state the trade-off explicitly: call is synchronous and blocks the caller (with a default 5-second timeout), giving backpressure and a guaranteed reply, while cast returns immediately with no delivery guarantee. Interviewers listening for depth want you to explain when each is safe to use, not just that both exist.

Performance and Distribution Questions

Erlang nodes form a cluster through distributed Erlang: each node registers with epmd (the Erlang Port Mapper Daemon) on startup, nodes authenticate one another using a shared magic cookie, and once connected, process communication — message sends, spawn, links, and monitors — works transparently across node boundaries using the same primitives as local processes. Interviewers like asking candidates to reason about network partitions here, and why relying purely on net_kernel or global-based registration doesn't substitute for a real consensus layer when split-brain-sensitive state is involved. On raw performance, candidates should be able to explain that the BEAM runs one scheduler thread per core with per-process reduction counting for fairness, that NIFs (natively implemented functions) offer C-level speed but can block an entire scheduler if they don't yield or run on a dirty scheduler, and that tools like observer, recon, and process_info are the standard way to diagnose message queue backlogs or memory bloat in a live production system.

🏏

Cricket analogy: Distributed Erlang nodes are like multiple international grounds all reporting into one shared ICC scoring system, authenticated by accreditation credentials, while a NIF blocking a scheduler is like a DRS review that takes too long and stalls the over, and recon is like the third umpire's replay tools used to diagnose exactly what went wrong.

  • Erlang processes are lightweight, VM-scheduled actors with isolated heaps and message-passing communication — not OS threads — which is why millions can run concurrently on one node.
  • "Let it crash" delegates recovery to supervisors, which use restart strategies (one_for_one, one_for_all, rest_for_one, simple_one_for_one) and a bounded restart intensity rather than defensive in-line error handling.
  • gen_server handles request/reply and cast-based work, gen_statem models explicit state machines (replacing gen_fsm), and gen_event fans events out to independently pluggable handler modules.
  • Hot code reloading relies on the code server holding at most two module versions at once and the code_change/3 callback to migrate a process's internal state across an upgrade without restarting it.
  • Pattern matching drives control flow in function clauses, case, and receive, including matching against already-bound variables; guards add conditions that can never raise exceptions, unlike if or case.
  • ETS is a shared, off-heap in-memory table readable by any process, the process dictionary is private mutable state scoped to one process, and Mnesia layers distributed, transactional persistence on top of ETS/DETS.
  • Distributed Erlang connects nodes via epmd and shared-cookie authentication so message passing works transparently across the cluster, while performance tuning depends on scheduler reduction counting, avoiding blocking NIFs, and tools like observer and recon.

Practice what you learned

Was this page helpful?

Topics covered

#Programming#ErlangStudyNotes#ErlangInterviewQuestions#Erlang#Interview#Questions#Interviewers#StudyNotes#SkillVeris#ExamPrep