Features
Feature packages are pluggable React modules that extend your Neutrino console with new UI and backend capabilities.
Features
A feature package is the unit of extensibility in Neutrino. Each feature is an npm package that contributes routes, sidebar navigation, and optionally a backend Cloudflare Worker to your console shell. Features are activated per platform and can be grouped into Stacks to share infrastructure.
What a feature package contains
Every feature package exports two things:
FeatureDefinition— describes what the feature does at runtime: its routes, navigation items, required permissions, and lifecycle hooks.featureManifest— describes how the shell should load it at build time: lazy-loading priority, domain grouping, default enabled state.
// Minimal feature definition
const featureDefinition: FeatureDefinition = {
id: "analytics",
version: "1.0.0",
displayName: "Analytics",
routes: [{ path: "/", component: "AnalyticsDashboard" }],
navigation: [{ label: "Analytics", path: "/", icon: "BarChart2", order: 50 }],
permissions: [
{ key: "analytics:read", label: "View Analytics", required: true },
],
requiresService: true,
serviceEnvKey: "VITE_ANALYTICS_API_URL",
};Permission key format (V06): Permission keys must match the pattern
^{featureId}:[a-z-]+$. Thenno feature validatecommand enforces this. Examples:billing:read,analytics:write-export,settings:admin-manage. Invalid:billing_read(underscores),Billing:Read(uppercase).
Auto-discovery via Vite plugin
Feature packages do not need to be manually registered. The console shell's Vite plugin scans all installed packages at build time, finds any package with "neutrino": { "type": "feature" } in its package.json, and automatically wires up its routes and navigation.
This means adding a feature to your platform is as simple as:
- Install the feature package
- Rebuild the console shell
- Activate the feature via the Neutrino console or CLI
The Vite plugin exposes discovered features through a virtual module (virtual:feature-registry) that the shell imports at startup.
The neutrino field in package.json
The auto-discovery contract lives in package.json:
{
"name": "@your-scope/feature-analytics",
"neutrino": {
"type": "feature"
}
}Only packages with "type": "feature" are picked up by the scanner. This prevents accidental inclusion of utility packages.
Shell integration
Once loaded, a feature integrates with the console shell through the ShellContext. The shell provides each feature with:
platform— the current platform ID and nametenant— the active tenant contextuser— the authenticated user with their permissionsfeatures— which other features are activenavigate— programmatic navigationenv—VITE_*environment variables
Features access this context through the useShell() hook from @neutrino-io/sdk/feature. This keeps features decoupled from the shell implementation — they only depend on the SDK contract, not on shell internals.
Backend Workers
If a feature declares requiresService: true, Neutrino provisions a Cloudflare Worker for it when the feature is activated on a platform. The Worker URL is injected into the console shell as the environment variable named in serviceEnvKey. Features in a Stack receive additional bindings for shared D1, R2, and KV resources.
Building your own feature
Authorship policy (current): feature authorship is restricted to Neutrino. Per ADR-006, the Neutrino platform does not accept client-submitted feature packages today; the
nno featurecommands are intended for Neutrino contributors. Platform operators activate the existing Neutrino-authored catalogue (billing, settings, stacks, …) through stack templates rather than building bespoke features.
For Neutrino contributors, the CLI scaffolds a new feature package:
nno feature init my-feature
cd my-feature
nno feature dev # start local dev with mock shell
nno feature validate # check compatibility before submittingSee the Feature Development guide for the full workflow. The marketplace / third-party model is a Phase 3+ consideration tracked in ADR-006.