Appearance
Building Features
This guide is for teams building feature apps on the Favn micro-frontend platform.
Quick start
bash
# 1. Scaffold a new feature
pnpm run create-feature my-feature
# 2. Develop with hot-reload
pnpm run dev:feature examples/feature-my-feature
# 3. Build and publish locally
pnpm run build
pnpm run publish:local
# 4. Run the host
pnpm run dev:host
# Visit http://localhost:3000/my-featureProject structure
examples/feature-my-feature/
manifest.json # Feature contract (routes, auth, shared deps)
package.json # Standard npm package
vite.config.js # Vite build config
vite.config.server.js # Server functions build config
scripts/publish.js # Local publish script
src/
main.jsx # Entry point (bootstraps React)
App.jsx # Root component
actions.server.js # Server functions (RPC)Bootstrapping your feature
Every feature entry point follows this pattern:
jsx
// src/main.jsx
import { createRoot } from 'react-dom/client';
import {
getBootstrapConfig,
getMountElement,
registerReactUnmount,
createFeatureHostApi,
} from '@favn/feature-sdk';
import App from './App.jsx';
const bootstrap = getBootstrapConfig({
defaultFeatureId: 'feature-my-feature',
defaultBasename: '/my-feature',
defaultDomElementId: 'feature-root',
});
const container = getMountElement(bootstrap.domElementId);
const root = createRoot(container);
root.render(<App bootstrap={bootstrap} />);
registerReactUnmount(root, bootstrap.featureId);registerReactUnmount does two things:
- Signals to the host that bootstrap succeeded (disabling the fallback error handler)
- Registers cleanup so the host can unmount your feature on page transitions
Shared dependencies
Declare shared deps to avoid bundling React/ReactDOM in every feature:
json
{
"shared": {
"react": { "singleton": true, "requiredVersion": "^19.0.0" },
"react-dom": { "singleton": true, "requiredVersion": "^19.0.0" },
"react-router-dom": { "singleton": true, "requiredVersion": "^7.1.0" }
}
}The host provides these via import maps. Your Vite config should externalize them:
js
// vite.config.js
export default {
build: {
rollupOptions: {
external: ['react', 'react/jsx-runtime', 'react-dom', 'react-dom/client', 'react-router-dom'],
output: { format: 'esm' },
},
},
};Reuse and data ownership
If you are building reusable UI modules, use featureType: "facet" and keep data orchestration in the consuming domain feature (the feature that owns the route/workflow and mounts the facet).
For patterns and flow diagrams, see Reuse and Data Flow.
Development workflow
Local development with HMR
bash
pnpm run dev:feature examples/feature-my-featureThis starts a standalone Vite dev server with:
- Hot module replacement
- Mock host event bus, store, and lifecycle
- RPC endpoint for server functions with mock ServerContext
- Shared deps served from workspace
Running against the full host
bash
pnpm run build
pnpm run publish:local
pnpm run dev:hostValidating compatibility
bash
pnpm run validate:compat # Standard check
pnpm run validate:compat:strict # Warnings become errorsError handling
The host provides three layers of error resilience:
- Resource load failures — If your JS/CSS fails to load, the host shows a fallback UI with a retry button.
- Bootstrap runtime errors — If your code throws during initial render, the host catches it and shows a fallback.
- React runtime errors — After successful mount, errors are handled by React's ErrorBoundary. Use
@favn/error-boundaryfor feature-level error boundaries.
The host also caches the last-known-good HTML for each feature path as a fallback.
CI checklist
Before deploying a feature:
- [ ]
pnpm run validate:compatpasses - [ ]
pnpm run lint:routespasses (no route conflicts) - [ ]
pnpm run doctorpasses (manifest schema validation) - [ ] Feature manifest has explicit
authRequiredsetting - [ ] Server functions enforce authorization checks for write operations
Reference example
See examples/feature-reference/ for a comprehensive example demonstrating all host API integrations, server functions with ServerContext, and team-owned authorization.