Features
Feature packages are pluggable React modules that extend your NNO console with new UI and backend capabilities.
Features
A feature package is the unit of extensibility in NNO. 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',
}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 NNO 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, NNO 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
Use the CLI to scaffold 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.