
OTP, the framework that provides standards to help build Erlang applications, uses applications to package code into units or components. This convention helps structuring your code into logical groups of modules and a way to start and stop the application's supervisors. Your Phoenix project is an application, but the Phoenix framework and Ecto are applications too.
An application is a component that can be compiled by itself. It can depend on other applications, and it can take its own configuration. Unlike in other languages, this convention provides a standardized way to specify how the VM should interact with it.
Aside from the compiled .beam
files containing virtual machine code, compiled applications consist of an application specification .app
file that tells the VM how to handle the application, and an optional application callback module that is used to start, run and stop the application.
Application Callback Modules
For applications with supervisors, the application callback module defines functions that start and stop the application. Applications without supervisors (usually libraries with functions you can call without no internal state) omit the callback module since the application doesn't need to be started.
In Elixir, an application callback module uses the Application
behavior. The behavior implements the start/2
and stop/1
callbacks. The former starts the application's main supervisor, and the latter is an optional callback that's used to clean up after stopping the supervisor.
Elixir's mix new
task automatically creates an application callback module when a new project is generated with the --sup
flag.
$ mix new --sup elixir_app
The generated project contains an application callback module in lib/elixir_app/application.ex
.
defmodule ElixirApp.Application do # See https://hexdocs.pm/elixir/Application.html # for more information on OTP Applications @moduledoc false use Application def start(_type, _args) do # List all child processes to be supervised children = [ # Starts a worker by calling: ElixirApp.Worker.start_link(arg) # {ElixirApp.Worker, arg}, ] # See https://hexdocs.pm/elixir/Supervisor.html # for other strategies and supported options opts = [strategy: :one_for_one, name: ElixirApp.Supervisor] Supervisor.start_link(children, opts) end end
When used, the Application
module adds a stub of the stop/1
function, which returns an ok-tuple. The generated start/2
function starts the app's main supervisor.
Application Specifications
Running mix compile.app
places the application's specification in the .app
file in the ebin
directory, and is one of the steps taken when compiling the app with mix compile
.
The specification contains Erlang terms which define the application. It lists the modules defined in the app, the version number and a list of other apps that the app depends on. It also specifies the module to be used as the callback that starts the app.
The specification file is based on the settings in the application’s mix.exs
file. To be able to generate the specification, each app must have a name and version number defined in its project function.
defmodule ElixirApp.MixProject do use Mix.Project def project do [ app: :elixir_app, version: "0.1.0" ] end end
Below is a minimal sample mix.exs
file, which only lists the project name and version number, yields a specification that lists Elixir’s default applications and specifies the modules in the app.
{application,elixir_app, [{applications,[kernel,stdlib,elixir]}, {description,"elixir_app"}, {modules,['Elixir.ElixirApp','Elixir.ElixirApp.Application']}, {registered,[]}, {vsn,"0.1.0"}]}.
Specifying and Configuring the Application Callback Module
Aside from the app's name and version number, a mix.exs
file generated with the --sup
option has an application
function with a mod
key.
defmodule ElixirApp.MixProject do # ... def application do [ mod: {ElixirApp.Application, []} ] end end
When generating the specification, it includes the callback module. This key points to the application's callback module, so the VM knows which module to use to start the application.
{application,elixir_app, [{applications,[kernel,stdlib,elixir,logger]}, {description,"elixir_app"}, {modules,['Elixir.ElixirApp','Elixir.ElixirApp.Application']}, {registered,[]}, {vsn,"0.1.0"}, {mod,{'Elixir.ElixirApp.Application',[]}}]}.
Tip: The list in the :mod
-tuple is used to pass configuration options to the application. Anything passed in ends up as the arguments to the callback module's start/2
function.
:applications
and :extra_applications
The applications
key in the specification lists all the applications that your app depends on. By default, mix compile.app
includes kernel
stdlib
and elixir
.
defmodule ElixirApp.MixProject do use Mix.Project def project do [ app: :elixir_app, version: "0.1.0", deps: [{:appsignal, "~> 1.0.0"}] ] end end
Dependencies are automatically added to the applications
list, and they’re automatically started before the application boots if they have an Application module.
{application,elixir_app, [{applications,[kernel,stdlib,elixir,appsignal]}, {description,"elixir_app"}, {modules,['Elixir.ElixirApp','Elixir.ElixirApp.Application']}, {registered,[]}, {vsn,"0.1.0"}]}.
To add more applications like Elixir’s logger
, you add them to the :extra_applications
key and they will subsequently be added to the existing list.
defmodule ElixirApp.MixProject do # ... def application do [ extra_applications: [:logger], mod: {ElixirApp.Application, []} ] end end
The :applications
key is used to explicitly specify the applications that are to be included in the specification. When used, only the listed applications and the defaults will be added. Any other dependencies are not automatically included.
Applications all the way down
Each seperate library, as well as your application itself, is an application. Some applications have a supervision tree, requiring them to have a callback module that takes care of starting and stopping the whole application.
Your application can depend on other applications, and each of these can have their own supervision trees and callback modules. Whatever's in there, it's always specified in the application specification file. Think of it as the formula for your Elixir. 😉
This concludes our overview of OTP applications in Elixir. We've tried convey some of the beauty of one of OTP's conventions. It is one of the many things we love about Elixir. If you do too, let us know what you'd like to see us write about, or subscribe to the Elixir Alchemy newsletter.
Wondering what you can do next?
Finished this article? Here are a few more things you can do:
- Subscribe to our Elixir Alchemy newsletter and never miss an article again.
- Start monitoring your Elixir app with AppSignal.
- Share this article on social media
Most popular Elixir articles
Using Mnesia in an Elixir Application
Learn about Mnesia and how to use it in an Elixir application.
See moreBuilding Compile-time Tools With Elixir's Compiler Tracing Features
Check out one of Elixir's latest features—compiler tracing—and find out why you should consider using it.
See moreMonitoring the Erlang VM With AppSignal's Magic Dashboard
In this post, we walk through monitoring the Erlang VM with the metrics automatically shown in AppSignal's Magic Dashboard.
See more

Jeff Kreeftmeijer
Become our next author!
AppSignal monitors your apps
AppSignal provides insights for Ruby, Rails, Elixir, Phoenix, Node.js, Express and many other frameworks and libraries. We are located in beautiful Amsterdam. We love stroopwafels. If you do too, let us know. We might send you some!
