October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix NowOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk7 min

Elixir OTP FAQs: GenServers, Supervisors, and Application Lifecycles

Understand the distinct roles of GenServers, supervisors, and OTP applications—and how calls, casts, child specs, restart policies, and application startup connect.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

In Elixir OTP, a GenServer provides a standard way to implement a process that handles requests and can own state; a supervisor starts and monitors child processes and applies restart rules; and an OTP application packages functionality with configuration and a start/stop lifecycle, commonly launching a top-level supervision tree. These pieces work together, but they solve different problems.

What is a GenServer in Elixir?

GenServer is a behavior for implementing the server side of a client-server relationship. It is not itself a process: using it defines callbacks for a process that handles messages, while the behavior supplies the process loop and standard interaction machinery. It also supports tracing and error reporting and fits into OTP supervision trees. The GenServer v1.20.4 documentation describes it as “A behaviour module for implementing the server of a client-server relation.”

As an Amazon Associate I earn from qualifying purchases.

A GenServer can own state and serialize access to it through messages. For example, a stack server might initialize a list in init/1, remove and return its head in handle_call/3, and add an item in handle_cast/2. Of the GenServer callbacks, only init/1 is required. Using use GenServer also defines child_spec/1 so the module can be started as a supervisor child.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Keep callers insulated from callback details with a small client API:

defmodule Stack do
  use GenServer

  def start_link(initial  []) do
    GenServer.start_link(__MODULE__, initial)
  end

  def pop(server), do: GenServer.call(server, :pop)
  def push(server, item), do: GenServer.cast(server, {:push, item})

  @impl true
  def init(items), do: {:ok, items}

  @impl true
  def handle_call(:pop, _from, [item | rest]), do: {:reply, item, rest}
  def handle_call(:pop, _from, []), do: {:reply, nil, []}

  @impl true
  def handle_cast({:push, item}, items), do: {:noreply, [item | items]}
end

This example shows the callback shape, not a complete production stack API. In a real application, decide explicitly how an empty pop should be represented and whether a push needs confirmation.

When is a GenServer appropriate?

Use one when the work benefits from a long-lived process identity, message handling, serialized ownership of mutable state, or supervision as part of an application. A process is not automatically the right home for every value that changes. If a counter can be updated by passing an integer into a function and returning the next integer, ordinary functions and values are simpler.

Choice What it provides Useful question
GenServer Process identity, message handling, serialized state ownership, and lifecycle integration Does this need to be a long-lived process that receives messages?
Plain functions and values Explicit inputs and outputs without a server process Can callers pass the value in and use the returned value?

What is the difference between GenServer.call and GenServer.cast?

GenServer.call/2 is synchronous from the caller’s perspective: it sends a request, waits for a reply, and dispatches to handle_call/3. GenServer.cast/2 sends an asynchronous message and dispatches to handle_cast/2; it does not return an application-level reply confirming that the requested work finished.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Operation Server callback Caller coordination Use when
call handle_call/3 The caller waits for a server reply The caller needs a result or must coordinate its next step with the server’s response
cast handle_cast/2 The caller sends without waiting for an application-level completion reply The caller can proceed without confirmation of the operation’s result

Use the interaction that matches the contract callers need. A cast is not a guarantee that application work succeeded, and neither choice should be treated as a universal performance ranking. Messages sent directly to the process rather than through these APIs can be handled with handle_info/2.

What does a supervisor do in Elixir?

A supervisor is a process that starts and monitors child processes according to child specifications. When a child terminates, the supervisor uses the child’s restart setting and its own strategy to decide what happens next. Supervisors provide structure for application startup, shutdown, and fault recovery. The Supervisor v1.20.4 documentation says, “Supervision trees provide fault-tolerance and encapsulate how our applications start and shutdown.”

Restarting a process does not magically recover its in-memory state. If a GenServer crashes and is started again, its init/1 runs again. A counter initialized to zero, for example, returns to zero unless its state is restored from another source.

What is a child specification?

A child specification tells a supervisor how to start and manage a child. It includes an identifier and start instructions, along with restart and shutdown configuration. A child may be specified as a map, or as a module or {module, argument} when that module provides child_spec/1. A module using GenServer gets a default child specification, which can be customized if the application needs different options.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What is the difference between one_for_one and one_for_all?

A supervisor strategy describes how a child’s termination affects its siblings. Choose it to reflect real lifecycle dependencies, not as a default unrelated to how the processes work.

Strategy Effect when a child terminates Fits when
:one_for_one The supervisor restarts the failed child without restarting its siblings Children are independent enough to continue when one is replaced
:rest_for_one The supervisor restarts the failed child and children started after it Later children depend on an earlier child’s lifecycle; for example, a connection process starts before workers that use it
:one_for_all The supervisor restarts all children if one terminates The children need to be brought back together as a group

These strategies govern the affected children; the child restart setting separately determines whether a particular termination triggers a restart.

What do the restart values mean?

Child restart value Restart behavior
:permanent Always restart the child when it terminates
:temporary Never restart the child
:transient Restart after abnormal termination, but not after normal termination or a shutdown reason

A long-running service is commonly permanent, while a finite task may need different semantics. Treat the restart value and supervisor strategy as separate choices: one says whether a child should restart; the other says which related children are affected.

How do I start a GenServer under a supervisor?

Define a child with start_link/1 and a child specification, then include it in the supervisor’s children list. The usual pattern is for the supervisor to start the server, rather than starting it separately and leaving it outside the tree.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  1. Define the server module and its initialization callback:

    defmodule Counter do
      use GenServer
    
      def start_link(initial  0) do
        GenServer.start_link(__MODULE__, initial, name: __MODULE__)
      end
    
      def value, do: GenServer.call(__MODULE__, :value)
      def increment, do: GenServer.cast(__MODULE__, :increment)
    
      @impl true
      def init(initial), do: {:ok, initial}
    
      @impl true
      def handle_call(:value, _from, count), do: {:reply, count, count}
    
      @impl true
      def handle_cast(:increment, count), do: {:noreply, count + 1}
    end
  2. Place the child in a supervisor’s child list and start the supervisor:

    children = [Counter]
    
    Supervisor.start_link(children, strategy: :one_for_one)

    The module form works because use GenServer defines child_spec/1. The supervisor starts the child via its start function and monitors it. In an application, this supervisor is usually returned by the application callback rather than started independently.

For a named server, the name must be unique among running processes. If the supervisor restarts the server, callers using that registered name can address the new process; callers holding an old process identifier cannot use it as though it were the replacement.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

What is an OTP application?

An OTP application is a standardized package of functionality with configuration and a lifecycle. It is not the same thing as an operating-system process. Applications can be loaded, started, and stopped; the Application v1.20.4 documentation states, “Applications are loaded, started, and stopped.” A Mix project declares application information and can define an application callback module. Its start/2 callback commonly starts and returns the top-level supervisor.

What is a supervision tree?

A supervision tree is a hierarchy of supervisors and child processes. A top-level supervisor can supervise other supervisors as well as workers, giving the application a structured way to start components, stop them, and respond to failures. The tree is the process-management structure; the application lifecycle is the package-level mechanism that starts and stops that structure.

How does an Elixir application start and stop?

  1. The application is loaded, making its code and application information available.

  2. When started, its callback module’s start/2 is invoked if one is configured. That callback typically starts a top-level supervisor and returns it as the application’s supervision root.

    Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  3. When the application is stopped, OTP shuts down its process tree according to the children’s shutdown configuration.

The application controller manages application lifecycle operations; an application does not imply one operating-system process. Processes in the supervision tree run on the Erlang VM.

How does application configuration work?

Each application has an application environment: a keyword list mapping atoms to terms. This is distinct from the operating-system environment, and the Application API cautions libraries against using application environment as general-purpose global storage.

In a Mix project, config/config.exs is loaded at build time, while config/runtime.exs is loaded at runtime just before the application starts. Put values that need to be supplied or resolved at deployment/runtime in the runtime configuration rather than assuming build-time configuration will be recalculated on the target system.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Which Elixir version do these examples target?

The official documentation index identified Elixir v1.20.4 as stable when checked on 2026-10-04, and listed support for Erlang/OTP 27, 28, and 29. The installation documentation says Elixir v1.20.4 requires Erlang/OTP 27.0 or later. These requirements can change; check the official supported-version documentation and the installation guide against the Elixir and OTP versions installed on your system.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Outdated Drivers Are Slowing You DownFree scan - exact matches
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.