This paper presents the formal semantics of concurrency in Core Erlang, an intermediate language for Erlang, along with a notion of program equivalence (based on barbed bisimulation) that is able to model equivalence between programs that have different communication structures but the same observable behaviour. The novelty in our formalisation is its extent: it includes semantics for messages and exit and link signals, in addition to most of Core Erlang’s sequential features. Furthermore, unlike previous studies, this work formalises message receipt using primitive operations, consistent with the standard as of Erlang/OTP 23. In this novel formalisation, we show some generally applicable program equivalences (such as process identifier renaming and silent evaluation) and present a practical case study featuring the equivalence of sequential and concurrent list processing.