Erlang is a general-purpose programming language and runtime system originally developed at Ericsson for building telecommunications systems that must remain available, responsive and maintainable despite failures. Its name comes from Agner Krarup Erlang, the Danish mathematician whose work in queuing theory influenced telecommunications engineering. Joe Armstrong, Robert Virding and Mike Williams were central to its development, with the language emerging in the 1980s from Ericsson's research into programmable telephone-switching systems.
Erlang was designed around a collection of requirements that were unusually demanding for mainstream programming languages of the period: very large numbers of concurrent activities, distributed execution, fault isolation, hot code replacement and continued operation while individual components fail. The language therefore differs fundamentally in emphasis from languages primarily designed around sequential computation or direct manipulation of shared mutable state. Erlang is dynamically typed, function-oriented, expression-based and strongly associated with immutable data, lightweight processes and message passing. Although it can be used for ordinary application programming, its most distinctive significance lies in systems where concurrency, distribution and availability are central architectural requirements.
Erlang's concurrency model is based on extremely lightweight processes rather than operating-system processes or conventional language-level threads that routinely share memory. A process has its own state and mailbox and communicates with other processes by sending messages. Because processes do not normally share mutable memory, many classes of race conditions and locking problems can be avoided or reduced. Process creation is intentionally inexpensive, allowing applications to contain very large numbers of concurrent processes.
A process can send a message using the exclamation operator and receive matching messages through a receive expression. Pattern matching determines which messages are handled, while selective receive permits a process to choose messages matching particular structures. This model is particularly useful for servers, protocol handlers, worker pools, actors and distributed components.
Erlang processes are managed by the Erlang runtime system rather than being mapped one-for-one to operating-system processes, allowing the runtime to schedule many concurrent activities over a comparatively small number of execution threads. The model became one of the defining influences on later actor-oriented and concurrent programming systems.
Erlang's functional programming model uses immutable data, recursion, pattern matching and higher-order functions as fundamental mechanisms. Variables are single-assignment within a particular scope, meaning that once a variable has been bound it cannot ordinarily be rebound to a different value. Lists, tuples, maps, binaries and other data structures are manipulated by constructing new values rather than by modifying shared objects in place.
Functions are first-class values, allowing functions to be passed as arguments, returned from other functions and stored for later use. Pattern matching is used extensively in variable binding, function clauses and message handling, so program structure often expresses the expected shape of data directly. Erlang functions may contain multiple clauses distinguished by patterns and guards, producing a style in which data representation and control flow are closely integrated. Recursion is consequently more important than traditional imperative loop constructs, although the runtime performs tail-call optimisation so suitable recursive functions can execute without accumulating a conventional call stack. These characteristics make Erlang programs naturally suited to decomposing systems into independent transformations and communicating processes.
Fault tolerance in Erlang is strongly associated with the principle commonly summarised as "let it crash", although this does not mean that Erlang applications are intended to ignore errors. Instead, developers commonly isolate failures within processes and use supervision mechanisms to detect abnormal termination, restart failed components and preserve the operation of unaffected components.
A supervisor maintains a set of child processes according to a defined strategy, such as restarting one child, several children or an entire group when failures occur. Supervision trees provide a structured hierarchy for managing failure, making recovery part of the architecture rather than an afterthought added through pervasive defensive checks. Erlang also provides links and monitors through which processes can observe one another's termination.
The approach is particularly appropriate where transient component failures are expected and recovery is preferable to shutting down an entire service. Fault isolation does not make arbitrary software automatically reliable: application state, external dependencies, data corruption and incorrectly designed restart strategies can still cause serious failures. The significance of Erlang's approach is that the language and runtime provide explicit mechanisms for modelling failure, monitoring components and recovering from many classes of runtime error.
Distribution is another fundamental aspect of Erlang. Erlang nodes can communicate using the same process and message-passing abstractions used inside a single runtime, allowing applications to be distributed across machines without requiring every component to adopt an entirely different programming model. Processes can have globally addressable identities and messages can be delivered between nodes using Erlang's distribution mechanisms. The runtime provides facilities for node discovery, process monitoring, remote procedure calls and distributed supervision.
This model was developed for telecommunications environments in which systems were expected to operate across multiple processors and machines and continue functioning despite individual component failures. Distributed Erlang nevertheless has practical boundaries: network partitions, latency, node failure, version compatibility, security and split-brain conditions must be addressed by system architecture. A distributed message is not equivalent to a local function call because networks can fail and communication can be delayed or lost according to the relevant transport and system configuration. Erlang's value therefore lies not in eliminating distributed-systems complexity but in giving developers a consistent process-oriented model with built-in support for many distributed operations.
The Erlang runtime environment is commonly referred to as the BEAM ecosystem, with BEAM being the virtual machine used by modern Erlang systems and also by other languages such as Elixir. Historically, Erlang source code has been compiled into intermediate representations executed by the virtual machine, which provides scheduling, garbage collection, process management, networking facilities and other runtime services.
The runtime's scheduler distributes runnable Erlang processes across available execution resources and attempts to prevent a single process from monopolising an execution scheduler indefinitely. Garbage collection is performed on a per-process basis, which can help limit the impact of memory-management activity associated with individual processes. Erlang also supports binary data types and efficient handling of large binary objects, which is particularly relevant to networking and telecommunications.
Hot code loading is another important capability: under suitable conditions, running systems can load new versions of modules while remaining operational. This capability was designed for systems where shutting down to install software updates could be unacceptable. Correct hot upgrades require careful versioning and release engineering, however, and are not a substitute for comprehensive deployment and rollback procedures.
Erlang has been used in telecommunications infrastructure, messaging systems, distributed databases, networking software, financial services and other applications where concurrency and availability are important. Ericsson's AXD and related telecommunications products helped demonstrate the language's original industrial purpose, while later systems such as WhatsApp used Erlang extensively for large-scale messaging infrastructure. The language's process model also influenced software outside telecommunications, particularly systems built around the actor model.
Erlang's standard library, commonly known as OTP, is particularly significant because it supplies reusable behaviours and infrastructure for constructing production systems. OTP includes abstractions such as generic servers, supervisors, finite-state machines and application management facilities, allowing developers to build systems according to established concurrent-system patterns rather than implementing process management from scratch. Consequently, understanding Erlang in isolation from OTP gives an incomplete picture of how Erlang is commonly used professionally. The language itself supplies syntax and semantics, while OTP supplies a substantial framework for organising long-running concurrent applications.
Erlang's advantages include lightweight concurrency, mature fault-management mechanisms, immutable data, strong support for distributed applications, hot-code capabilities and a runtime designed around long-running systems. Its limitations include a comparatively unusual syntax for developers accustomed to mainstream object-oriented languages, dynamic typing that can defer certain classes of errors until execution, a smaller ecosystem than languages such as JavaScript, Python or Java, and specialised performance considerations when interfacing with native code or CPU-intensive workloads.
Erlang is not automatically faster than lower-level compiled languages for numerical computation, and its strengths are generally more visible in highly concurrent, message-oriented workloads than in programs dominated by intensive numerical processing. Erlang's influence nevertheless extends beyond its own adoption because its process model, supervision philosophy and runtime architecture helped establish patterns later adopted or adapted by languages and frameworks including Elixir and other actor-oriented systems. Its enduring importance is therefore both practical and historical: it remains a functioning programming platform for concurrent distributed software while also serving as a major example of a language whose semantics, runtime and standard frameworks were deliberately shaped around reliability and concurrency.