Skip to content
Hot Code Reload
step 1/7

Reading — step 1 of 7

Learn

~3 min readgen_statem, Hot Code Reload, Performance

Hot code reload is Erlang's signature feature: replace a running module's code without stopping the VM. Foundation of Ericsson's nine-nines uptime.

How it works

The BEAM keeps TWO versions of each loaded module:

  • The current version (latest loaded)
  • The old version (the one before)

Processes execute the version they were running when called. New calls into the module use the current version.

Reloading at the shell

%% Compile and load:
1> c(my_mod).
{ok, my_mod}

%% Module's code is now updated. Existing processes finish their current call
%% with the OLD code, then their NEXT call uses the new code.

For a long-lived gen_server: when you reload its module, the next message it processes uses the new code. Mid-call work continues with the old.

Forcing a process to use new code

The canonical pattern:

handle_call(Msg, From, State) ->
    %% normal handling
    ?MODULE:handle_call(Msg, From, State).    %% fully-qualified call

The fully-qualified call (?MODULE:fn(...)) ALWAYS goes through the latest version. Internal calls (fn(...) without prefix) stay with the version the process was loaded with.

In gen_server's loop, the framework does fully-qualified calls into your callbacks — so reloading your module immediately affects new messages.

code:purge / code:soft_purge

The BEAM only allows TWO versions. Loading a third triggers a purge of the oldest:

code:soft_purge(my_mod).      %% safe — fails if any process is still on old version
code:purge(my_mod).            %% kills processes still on old version!

If a process is in the middle of a long call to the old version when a third version loads, purge will kill it. soft_purge returns false instead — letting you decide.

Code change callback (gen_server)

For sophisticated upgrades that need to migrate state:

code_change(OldVsn, State, _Extra) ->
    %% Migrate State from OldVsn to current version
    NewState = transform_state(OldVsn, State),
    {ok, NewState}.

The OTP release tooling triggers code_change calls during in-place upgrades.

Release upgrades

For production: package upgrades as release packages (.tar.gz with new beams + upgrade scripts). The OTP release_handler applies them with proper sequencing — minimizing downtime.

Why this matters

WhatsApp and Ericsson's AXD301 switch use hot code reload to deploy code changes without dropping connections. Phone calls connected before the upgrade continue; new calls hit new code.

Most web stacks reach for blue-green deployments or rolling restarts. Erlang lets you do in-place upgrades when downtime really isn't an option.

When NOT to use

  • Simple changes can be done with a restart — easier to reason about
  • Schema migrations / large state shape changes — code_change has limits
  • Upgrades that affect supervision tree shape — needs careful planning

Most Erlang/Elixir teams these days deploy via standard releases + restart. Hot reload is a tool for genuinely 24/7 systems where seconds of downtime aren't acceptable.

Common mistakes

  • Internal calls vs fully-qualifiedf(X) (local) stays with old version after upgrade until the process restarts. Use ?MODULE:f(X) if you want it to follow the latest.
  • purge over soft_purge — purge kills processes. soft_purge returns false; you handle the case.
  • Skipping code_change for state changes — old state shape may not match new code. Migrate explicitly.
  • Upgrading supervision trees — supervisor child_spec changes don't apply automatically; needs supervisor:terminate_child + start_child or restart.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…

Hot Code Reload — Erlang Advanced