A minimal PhoenixKit plugin module — use this as a starting point for your own.
This module demonstrates every required and commonly-used optional callback from
the PhoenixKit.Module behaviour. Copy this project, rename it, and replace the
callbacks with your own logic.
How it works
use PhoenixKit.Modulemarks this module as a plugin (persists a@phoenix_kit_moduleattribute in the.beamfile).- PhoenixKit scans
.beamfiles at startup and discovers this module automatically — no config line needed. - The callbacks below tell PhoenixKit how to integrate the module: admin tabs, permissions, enable/disable toggling, etc.
Installation
Add to your parent app's mix.exs:
{:phoenix_kit_hello_world, "~> 0.1.0"}Or for local development:
{:phoenix_kit_hello_world, path: "../phoenix_kit_hello_world"}Then run mix deps.get. That's it — the module appears in the admin
Modules page and sidebar automatically.
What you get for free
- Admin sidebar tab (appears/disappears when module is toggled)
- Entry in the admin Modules page with enable/disable toggle
- Permission key in the roles/permissions matrix
- Live sidebar updates (no page reload needed when toggling)
- Route auto-generated at compile time from the
live_viewfield
Navigation paths
All href attributes and redirect/2 calls must go through
PhoenixKit.Utils.Routes.path/1 — never use relative paths.
Create a Paths module (e.g., MyModule.Paths) that wraps
Routes.path/1 to centralize your module's paths in one place.
See the README for the full pattern.
JavaScript
External modules cannot inject into the parent app's JS build pipeline.
All JavaScript must be inline <script> tags in your templates.
Register hooks on window.PhoenixKitHooks — PhoenixKit spreads this
into the LiveSocket automatically. See the README for full details.
Callbacks overview
| Callback | Required? | What it does |
|---|---|---|
module_key/0 | Yes | Unique string key (used in settings, permissions) |
module_name/0 | Yes | Human-readable name (shown in admin UI) |
enabled?/0 | Yes | Whether the module is currently on |
enable_system/0 | Yes | Turn the module on (persists to DB) |
disable_system/0 | Yes | Turn the module off (persists to DB) |
permission_metadata/0 | No | Icon, label, description for permissions UI |
admin_tabs/0 | No | Tabs to add to the admin sidebar |
settings_tabs/0 | No | Tabs to add to the admin settings page |
children/0 | No | Supervisor child specs (GenServers, workers, etc.) |
version/0 | No | Version string (default: "0.0.0") |
get_config/0 | No | Stats/config map shown on the Modules page |
route_module/0 | No | Module providing custom route macros |
user_dashboard_tabs/0 | No | Tabs for the user-facing dashboard |
migration_module/0 | No | Versioned migration coordinator module |
required_integrations/0 | No | Integration provider keys this module needs |
integration_providers/0 | No | Custom provider definitions to contribute |
Summary
Functions
Admin sidebar tabs for this module.
OTP apps whose templates Tailwind should scan for CSS classes.
Disables the module. Same pattern as enable_system/0.
Enables the module by persisting a boolean setting.
Whether the module is currently enabled.
Unique key for this module. Used in settings, permissions, and PubSub events.
Display name shown in the admin UI.
Permission metadata for the roles/permissions matrix.
Version string. Shown on the admin Modules page.
Functions
Admin sidebar tabs for this module.
Each tab needs at minimum: :id, :label, :path, :level, :permission.
Key fields:
:id— unique atom across ALL modules (prefix with:admin_yourmodule):path— must start with/adminand use hyphens, not underscores:permission— must matchmodule_key/0so custom roles get proper access:group— use:admin_modulesto appear in the Modules section of the sidebar:priority— controls sort order (higher = further down). Built-in modules use 500-620; use 640+ for external modules:live_view—{Module, :action}tuple; PhoenixKit auto-generates the route:icon— Heroicon name (optional, shown in sidebar):match—:exactor:prefixfor active-state highlighting
Return [] to have no admin tabs (default).
OTP apps whose templates Tailwind should scan for CSS classes.
Disables the module. Same pattern as enable_system/0.
Enables the module by persisting a boolean setting.
update_boolean_setting_with_module/3 stores the value and tracks which
module owns the setting. The third argument must match module_key/0.
Whether the module is currently enabled.
Reads from the DB-backed settings table. Defensive against three failure modes that can hit before/around DB availability:
rescue _: DB not running, table missing, schema mismatch, etc.catch :exit, _: connection pool checkoutEXIT(e.g. when a test sandbox owner has just stopped — test-environment artifact, but harmless to handle in production code too).
All branches return false so callers don't need to special-case
startup ordering.
Unique key for this module. Used in settings, permissions, and PubSub events.
Display name shown in the admin UI.
Permission metadata for the roles/permissions matrix.
The :key MUST match module_key/0 — PhoenixKit validates this at startup.
Icons use the hero- prefix (Heroicons via phoenix_heroicons).
Return nil to opt out of the permissions system entirely (default).
Version string. Shown on the admin Modules page.