Feature flags for Phoenix and Elixir — GenServer caching and LiveView integration
Sign up at flagbit.anethoth.com to get your SDK key. The free tier includes 1,000 evaluations/day.
# Add to mix.exs: {:req, "~> 0.4"}
defmodule MyApp.FlagBit do
use GenServer
@url "https://flagbit.anethoth.com/api/v1/evaluate"
@cache_ttl :timer.seconds(60)
def start_link(_), do: GenServer.start_link(__MODULE__, %{}, name: __MODULE__)
def init(state), do: {:ok, state}
def enabled?(flag_key, context \\ %{}) do
cache_key = {flag_key, context}
case GenServer.call(__MODULE__, {:get, cache_key}) do
{:ok, value} -> value
:miss ->
value = fetch_flag(flag_key, context)
GenServer.cast(__MODULE__, {:put, cache_key, value})
value
end
end
def handle_call({:get, key}, _from, state) do
case Map.get(state, key) do
{value, expires} when expires > System.monotonic_time(:millisecond) ->
{:reply, {:ok, value}, state}
_ -> {:reply, :miss, state}
end
end
def handle_cast({:put, key, value}, state) do
expires = System.monotonic_time(:millisecond) + @cache_ttl
{:noreply, Map.put(state, key, {value, expires})}
end
defp fetch_flag(flag_key, context) do
sdk_key = Application.get_env(:my_app, :flagbit_sdk_key)
case Req.post(@url,
json: %{flag_key: flag_key, context: context},
headers: [{"x-sdk-key", sdk_key}],
receive_timeout: 5000
) do
{:ok, %{body: %{"value" => value}}} -> value
_ -> false
end
end
end
# Phoenix controller
defmodule MyAppWeb.DashboardController do
use MyAppWeb, :controller
def index(conn, _params) do
user_id = conn.assigns.current_user.id |> to_string()
if MyApp.FlagBit.enabled?("new-dashboard", %{"user_id" => user_id}) do
render(conn, :index_v2)
else
render(conn, :index)
end
end
end
# LiveView
defmodule MyAppWeb.HomeLive do
use MyAppWeb, :live_view
def mount(_params, session, socket) do
show_beta = MyApp.FlagBit.enabled?("beta-features",
%{"user_id" => session["user_id"]})
{:ok, assign(socket, show_beta: show_beta)}
end
end
Feature flags complement BEAM's hot code loading — toggle features without even restarting the VM.
A/B test different LiveView component implementations in real-time.
Gradually migrate from one GenServer implementation to another with percentage rollouts.
Use distributed Erlang to sync flag states across all nodes in your cluster.
Define flags in your FlagBit dashboard with targeting rules and rollout percentages.
Call the evaluate endpoint from your Elixir/Phoenix app with user context for targeted rollouts.
Enable, disable, or adjust rollouts in real-time. No redeployment needed.
GenServer is Elixir-native — no external cache needed. It handles concurrent access safely and integrates with OTP supervision.
Yes — evaluate flags in mount/3 and assign the result. The flag value persists for the LiveView session.
Yes — ETS gives concurrent reads without bottlenecking on GenServer calls. Better for high-throughput scenarios.
Evaluate flags in channel join/3 to gate WebSocket features per user.
Free tier includes 1 project, 10 flags, and 1,000 evaluations/day. No credit card required.
Get Your Free API Key