Process State Management: What You’ll Learn

In the previous lesson, you sent and received messages between processes. As a brief reminder, a process can use receive to block and wait for messages, and it often calls itself recursively to stay alive. Today, we will build on that by having a process remember data across messages. This is called process state management, and it is a core part of how Elixir programs model state without mutable variables.

You will see how a process:

  • Holds state in a recursive loop
  • Updates that state when it receives messages
  • Replies to the caller with results
  • Shuts down cleanly

Note: In this lesson, we use raw spawn and receive to help you understand the fundamentals of process state and messaging. In real-world Elixir applications, you will typically use OTP abstractions like GenServer, Task, and Supervisor for process management and reliability. We will explore these OTP tools later in this course path.

The Receive Loop That Holds State

The following functions are part of a module we will call Counter. First, we define the core loop:

Explanation:

  • The current state is the count argument. It lives on the stack of this process.
  • {:increment, caller} updates the state, replies to the caller with the new value, then recurses with loop(new_count).
  • {:get, caller} does not change the state; it replies with the current count and recurses with loop(count).
  • :stop prints a message and returns, ending the process.
  • This is the same receive-and-recursion pattern you used before, now carrying state forward.
Starting the Counter Process

Next, we add a public start/1 function to the Counter module to initialize the state:

Explanation:

  • start/1 creates a new process that begins its loop with initial_value as state.
  • spawn returns the pid of the new process so you can send it messages.
  • The loop function is private to keep control inside the module.
Interacting With the Counter

Explanation:

  • Counter.start(0) launches the stateful counter with an initial count of 0.
  • You send {:increment, self()} to request an update; self() is your pid so the counter knows where to reply.
  • receive waits for {:count, value} and prints it.
  • {:get, self()} asks for the current count without changing it.
  • :stop tells the counter to print its final message and exit.
Summary and Next Steps

You now know how to keep state inside a process:

  • Store state as a function argument in a recursive receive loop.
  • Update state by creating a new value and tail-recursing with it.
  • Reply to callers so they can observe the state safely.
  • Stop cleanly on command.

This pattern is the foundation for building servers and agents in Elixir. Ready to make it second nature? Head to the practice section and bring this counter to life.

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal