FullstackPhoenix

Feature Flags for Phoenix with FunWithFlags

phoenixfeature-flagsfun-with-flagssaas

You're about to ship a new dashboard that replaces the one your existing customers know. Sending it to everyone at once is the kind of decision people regret. You want to enable it for a friendly customer first, then a beta cohort, then everyone — without a deploy at each step.

This feature installs FunWithFlags wired into your app behind two small wrappers. You never call FunWithFlags directly from a LiveView or context; you call MyApp.Feature.enabled?/2 or MyAppWeb.FeatureFlags.enabled?/2. That isolation pays for itself the day you want to swap the implementation or test the call site.

Toggle features without redeploying

A useful flag system has to be more than a config flag. It has to persist across nodes, react to admin changes quickly, and let you target by user or team — not just globally. FunWithFlags with the Ecto and PubSub backends covers that, and the wrappers keep the call sites domain-shaped instead of provider-shaped.

What This Feature Adds

  • {:fun_with_flags, "~> 1.13.0"} and {:fun_with_flags_ui, "~> 1.1.0"} added to mix.exs
  • Configuration that wires FunWithFlags to your existing MyApp.Repo for persistence and to Phoenix PubSub for cache invalidation across nodes
  • A migration that creates the fun_with_flags_toggles table (respecting your boilerplate's binary-id setting)
  • A MyApp.Feature module — the domain-level wrapper called from contexts and workers
  • A MyAppWeb.FeatureFlags module — the web-level wrapper that accepts assigns maps, conns, and LiveView sockets
  • An optional admin UI mount (via fun_with_flags_ui) for toggling flags from a browser
  • Generated actor implementations for User (when authentication is installed) and Team (when teams is installed)

How It Fits Into Your Phoenix Application

The two wrappers are the integration point. Application code never references the provider:

if MyApp.Feature.enabled?(:new_billing_dashboard, current_scope) do
render_new_dashboard()
else
render_legacy_dashboard()
end
if MyAppWeb.FeatureFlags.enabled?(:beta_export, socket) do
show_beta_export_button()
end

The actor protocol implementations decide what "this flag is on for me" means: by default, the user's id when authentication is installed, and the active team's id when teams is installed. That makes per-cohort rollouts a one-liner without a custom predicate every time.

Installation Notes

  • No hard feature dependencies. The user / team actor implementations are conditional — they are only generated when the corresponding features are installed.
  • The migration uses your existing Repo and primary-key type. Run mix ecto.migrate after install.
  • Decide who can toggle flags. If you mount fun_with_flags_ui, gate it behind the admin pipeline from the admin feature.
  • Flag values change at runtime; tests that depend on a specific flag value should set it explicitly.

Build This With Live SaaS Kit

Install saas_kit, then mix saaskit.feature.install fun_with_flags to get persistent, multi-node feature flags with domain-shaped wrappers in place from day one.