Erlang
let-it-crash
fault-tolerance
software-design
error-handling

Erlang's let-it-crash philosophy - applicable elsewhere?

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

Erlang's let it crash philosophy is often misunderstood as a license to ignore errors. That is not what it means. The real idea is to stop writing fragile recovery logic inside every component and instead build systems where failing components are isolated, replaceable, and supervised.

That design absolutely applies outside Erlang, but only if the rest of the architecture supports it. If a crash destroys irreplaceable in-memory state or takes down the whole process, then let it crash is just a bug with a slogan attached.

What Let It Crash Really Means

In Erlang and OTP, small processes do one job, avoid shared mutable state, and can be restarted by supervisors. The process is expected either to finish correctly or to fail fast. Recovery happens one level up in the supervision tree.

This works because three conditions are built in:

  • Isolation between units of work.
  • Cheap restart of failed units.
  • State stored in a place that can be reconstructed or recovered.

Without those conditions, crashing is expensive and dangerous.

Where the Philosophy Transfers Well

The approach works well in systems that already separate control flow from failure recovery:

  • Background job workers that can be retried from a queue.
  • Microservices running behind a restart policy in Kubernetes or systemd.
  • Actor-style runtimes such as Akka or Orleans.
  • Stateless request handlers where a failed request can be retried safely.

It is also useful at module level. Even in a regular application, it is often better for a component to reject an impossible state immediately than to limp forward after corrupting data.

A Simple Supervisor Example Outside Erlang

Python does not give you Erlang supervision out of the box, but you can model the same idea with a parent process that restarts a worker:

python
1import multiprocessing as mp
2import random
3import time
4
5def worker():
6    print("worker started")
7    time.sleep(0.5)
8    if random.random() < 0.7:
9        raise RuntimeError("simulated failure")
10    print("worker finished cleanly")
11
12def supervise(max_restarts=5):
13    restart_count = 0
14
15    while restart_count < max_restarts:
16        proc = mp.Process(target=worker)
17        proc.start()
18        proc.join()
19
20        if proc.exitcode == 0:
21            print("supervisor: success")
22            return
23
24        restart_count += 1
25        print(f"supervisor: restart #{restart_count}")
26        time.sleep(1)
27
28    print("supervisor: giving up")
29
30if __name__ == "__main__":
31    supervise()

This is not OTP, but it shows the principle. The worker does not contain complicated self-repair logic. The supervisor decides whether and how to restart.

What Makes This Safe

The philosophy only works when restart is cheaper than local repair. That means you should externalize important state and keep worker startup predictable.

For example, a request handler that reads from a database, computes a response, and writes structured logs is a good fit. If the process crashes, a replacement can serve the next request without needing hidden state from the dead process.

A trading engine keeping critical state only in memory is a poor fit. If that process crashes, blind restart may lose or duplicate business actions unless the system was designed around durable event logs and idempotency.

Good Uses in Non-Erlang Systems

The idea translates well into day-to-day engineering practices:

  • Fail fast on invariant violations instead of guessing.
  • Use supervisors, process managers, or orchestration platforms to restart units.
  • Keep services stateless where possible.
  • Make work idempotent so retries are safe.
  • Persist state before acknowledging success.

Kubernetes, for example, makes restart policies easy, but Kubernetes alone does not give you Erlang semantics. You still have to design services so a restarted container can recover cleanly.

Where It Does Not Transfer Cleanly

Some environments punish crashing:

  • User-facing desktop apps where repeated crashes destroy trust.
  • Embedded control systems with strict real-time behavior.
  • Libraries that run in another host process.
  • Code paths performing irreversible side effects without idempotency.

In those cases, defensive validation and local error handling still matter. The lesson from Erlang is not always crash. The lesson is crash small, crash safely, and recover at the right boundary.

Common Pitfalls

The biggest mistake is applying the philosophy without supervision. If a process crashes and nothing restarts it, you have copied only the failure half of the model.

Another mistake is hiding non-durable state inside a worker and assuming restart is harmless. If restart loses business state, the system was not ready for let it crash.

Teams also misuse the phrase to justify missing validation. Fast failure is valuable, but only after you have drawn a boundary between recoverable input errors and truly impossible states.

Finally, do not build infinite restart loops without backoff or escalation. A supervisor should know when to stop retrying and mark the system unhealthy.

Summary

  • 'Let it crash means fail fast inside isolated components and recover through supervision.'
  • The idea works outside Erlang when restart is cheap and critical state is durable.
  • It fits stateless workers, queued jobs, and actor-like systems better than monolithic stateful processes.
  • Crashing is not a substitute for validation, idempotency, or supervision.
  • The philosophy transfers well only when the architecture is designed for safe restart.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.