Hi everyone,
I’m happy to introduce Crank, a library that makes modelling complex stateful logic in Elixir much more enjoyable and maintainable.
Crank draws inspiration from the long evolution of finite state machines across Erlang and Elixir — from early recursive function patterns to modern OTP behaviours — and brings those ideas together in a clean, modern form. It lets you define your finite state machine as pure, immutable Elixir code first. This gives you state machines that are:
- Extremely clear and self-documenting (one explicit callback per transition)
- Trivially testable without starting any processes
- Fully reusable in any context — tests, LiveView, Oban jobs, scripts, or business logic layers
- Easy to reason about and debug
When your application needs real process features (supervision, timeouts, synchronous replies, telemetry, etc.), you can promote the exact same module to run as a full OTP :gen_statem using Crank.Server with almost no extra code.
You write the logic once in a clean, functional style, and get the best of both pure data-driven design and battle-tested OTP behaviours.
Example
defmodule MyApp.Door do
use Crank
@impl true
def init(_opts), do: {:ok, :locked, %{}}
@impl true
def handle(:unlock, :locked, data), do: {:next_state, :unlocked, data}
def handle(:lock, :unlocked, data), do: {:next_state, :locked, data}
def handle(:open, :unlocked, data), do: {:next_state, :opened, data}
def handle(:close, :opened, data), do: {:next_state, :unlocked, data}
end
Pure usage
machine =
MyApp.Door
|> Crank.new()
|> Crank.crank(:unlock)
|> Crank.crank(:open)
machine.state # => :opened
As a supervised process
{:ok, pid} = Crank.Server.start_link(MyApp.Door)
Same module, same logic — two powerful execution modes.
Crank is small, well-documented, and has no dependencies beyond OTP. It is production-ready and designed to feel like a natural part of the Elixir ecosystem.
You can find the full documentation and more examples (including a vending machine) here:
Hexdocs: Crank — Crank v0.2.0
Let me know what you think or if you have any questions!






















