
If you programmed anything with Elixir (if not, check our introductory Elixir Interview) one of the first things you encounter are modules. But what exactly is a Module and how do they work internally?
The basics
Modules are one of the key building blocks of the elixir language and also of the BEAM, which is the runtime for elixir code. Simply put, a module is a collection of functions and attributes. All code that is executed must be loaded into the runtime at first. The code loading is done on a module level, meaning the runtime can only load modules. Therefore, all elixir code has to reside in a module.
Let’s create an Elixir module
In all examples the interactive elixir shell is used. If you want to follow along start one and type the following.

At first we created a module named MyModule
and a function named myFunction
that belongs to that module by using demodule
and def
. The defmodule
command returns a tuple with four elements:
the atom
:module
name of the module that was defined
a binary representation of the module called object code
the result of the last expression in the do block
Then we called the function myFunction
of the MyModule
module with the command MyModule.myFunction
and got 4711
as return value of the call.
What actually happened here?
The defmodule
command did two things.
It compiled our module definition into object code. That object code is a binary representation of the module that can be loaded by the runtime. Beside other things it contains:
The name of the module
The actual instructions that get executed by the runtime when a function is called. These instructions are called bytecode
A lookup table with all function names and a reference on where in the object code to find the function’s bytecode
It loaded the object code into the runtime.
When the MyModule.myFunction()
was called the runtime, with the help of the lookup table, found and executed the bytecode for that function. In case of myFunction
that bytecode returns the literal 4711
to the caller.
Exploring Elixir object code
Each module in Elixir is compiled seperatly resulting in one binary e.g. object code that includes the actual instructions for the runtime as well as as metadata in the form of module variables (we cover module variables later).
Loading object code
The next example will show how a module can be loaded from object code. Because defmodule
will not only create the object code but will also load it into the runtime and i want you to see how the loading happens seperatly, the object code has to be written to a file. To illustrate that MyModule
is loaded there is also an additional call to my_function
.
The actual format of the object code does not matter at the moment what’s important is that each module has its own binary, which is object code.

In a newly opened iex MyModule
, as expected, is not available. After the object_code was read from the file and loaded with the :code.load_binary
function it becomes available.

Auto loading object code
In the code loading example the file in which the object code was stored was named my_module_object_code.bin
but if you rename that file to my_module.beam
it will get loaded by the iex on startup automatically. The .beam
filename makes the difference here. Every file that resides inside the directory you are in when executing the iex command and has a name that ends with .beam
is loaded on iex startup.
Compiling Elixir files
As you probably know elixir source code is stored in files that have names ending with .ex
or sometimes .exs
.
Let’s do the same with the MyModule
module by creating a file my_module.ex
and putting the module definition in it.
1 2 3 4 5 |
|
Next we start a iex inside the same folder where the my_module.ex
file is located. When we try to execute our function like before we just get an error that informs us that the module MyModule
is not loaded.

The command c("my_module.ex", ".")
compiles and the file and loads the module/s defined in it. Furthermore it writes a beam file to the folder provided as second parameter which is the current folder in the example.

A file with the name Elixir.MyModule.beam
was created and sure enough when the iex is restarted the module is available without the need to compile the elixir code again.

In practice all this is handled behind the scenes by mix the elixir build tool.
Structuring Elixir code with modules
After considering the compile and runtime aspects of modules let’s explore (source-) code side of things next.
There are many ways you can use modules to structure your code and you can, and probably already have, read about this topic in many books, articles and so on. What i want to do is to show the basic building blocks which can be used to build more complex patterns for structuring code.
Contextualize functions with namespaces
Functions that, on an conceptual level, belong together can be put inside a module that then gives these functions context.
1 2 3 4 5 6 7 |
|
The two speek
functions are called with Greet.speek()
and Farewill.speek()
which gives them either the greet or the farewell context.
Another nice thing you can do, but that we will not discuss deeply here, is the creation of one data structure inside each module. These data structures called structs are often used to define the structure of the data on which the functions of the module operate.
Control the visibility of functions
This one is pretty simple. You can define functions to be callable from everywhere or only from functions that are part of the same module. Public functions are defined with def
and private functions are defined with defp
.
1 2 3 4 5 6 7 |
|
Inside the iex the callGreet.speek("Hans")
will return the expected result, but the call Greet.construct_message("Hans")
will result in an exception ** (UndefinedFunctionError) function Greet.construct_message/1 is undefined or private Greet.construct_message("Hans")
Annotate modules
Module attributes are the last thing you can put inside a module beside functions and structs. A module attribute is a key-value pair that attached to a module and can be set, accessed and to a degree modified, at compile time . This can be useful to define static values or pass additional data to the compiler. In this example the module attribute message
will be inlined and is available at runtime no more. The moduledoc
will be used by the compiler to add documentation to the object code. While the documentation is available at runtime the actual attribute is not.
1 2 3 4 5 6 7 8 9 10 11 |
|
To be precise there are module attributes that are also available at runtime and one can create module attributes with that property as well. This is however more cumbersome to write and only used for runtime related stuff. If you are not writing some kind of runtime or compiler you should not care about them and remember that module attributes are a compile time thing.
The Module module
One thing that can be slightly confusing is that elixir provides a module with the name Module
. It provides functions and macros for working with modules. For example one can create a module with Module.create/3
Wrapping up
Modules are one of the basic building blocks of elixir. They are not only a language feature but also a basic building block of the BEAM runtime. They are essential for compilation, code loading and execution.
With this knowledge we can dive deeper into what elixir actually is by exploring how it is implemented. But that is for another time.

Über den Autor
Raphael arbeitet als Softwareentwickler und Berater bei Inspired. Seine Spezialität ist die IT-Sicherheit in der Software Entwicklung. Bei Konzeption und Implementierung von Software versucht er immer auch den Blick von potenziellen Angreifern einzunehmen.
Allgemein beschäftigt er sich mit funktionaler Programmierung seit über fünf Jahren. Elixir ist seit zwei Jahren auf seinem Radar und seitdem in nahezu täglichem Einsatz.