App Boilerplate
Getting Started
Getting Started with Boilerplate App
The Boilerplate App serves as the source template for the FlowState CLI's create-app command. This guide walks you through creating a new app and integrating it into the FlowState ecosystem.
Prerequisites
Before creating a new app, ensure you have:
- FlowState CLI installed (
flowstatecommand available) - Working FlowState monorepo environment
- Yarn package manager
- Node.js 18+
Overview
Creating a new FlowState app involves:
- Scaffolding the app using the CLI
- Renaming boilerplate references
- Updating exports to follow naming conventions
- Integrating into Next.js container
- Integrating into Electron container
- Configuring the plugin manifest
- Verification
Step 1: Create the App Using CLI
Run the FlowState CLI to scaffold the new app:
flowstate create-app <app-name> --verbose
Example:
flowstate create-app process --verbose
This creates the app at packages/apps/flowstate-app-<app-name>/ with:
- Basic React app structure
- Plugin definition
- Tailwind CSS configuration
- TypeScript configuration
- Vite build setup
Expected output:
Creating new FlowState app: <app-name>
✓ Template copied
✓ Configuration files updated
✓ Dependencies installed
✓ Build passed
✓ Typecheck passed
✓ Successfully created: flowstate-app-<app-name>
Step 2: Rename Boilerplate References
The scaffolded app contains "Boilerplate" placeholder text that must be replaced.
Search for Boilerplate References
grep -r "Boilerplate\|boilerplate" packages/apps/flowstate-app-<app-name>/
Update All Files
Replace "Boilerplate" with your app name in these files:
| File | Changes |
|---|---|
src/components/Header.tsx | Update comment and title prop |
src/components/Sidebar.tsx | Update comment and title prop |
src/pages/HomePage.tsx | Update welcome text, description, and icon |
src/pages/UsersPageWrapper.tsx | Update comment |
src/pages/OrgsPageWrapper.tsx | Update comment |
src/pages/WorkspacesPageWrapper.tsx | Update comment |
src/plugin.ts | Update comment, name, and icon |
src/App.tsx | Update comment |
tailwind.config.js | Update path comment |
postcss.config.js | Update path comment |
Choose an Appropriate Icon
Update the icon import in src/plugin.ts and src/pages/HomePage.tsx:
import { Workflow } from 'lucide-react'; // Choose appropriate icon
Available icons: https://lucide.dev/icons/
Step 3: Update Exports (Naming Convention)
Edit src/index.ts to export the app component with a named export following the pattern <AppName>App:
// Main exports
export { <appName>Plugin } from './plugin';
export { App as <AppName>App } from './App';
export type { AppProps as <AppName>AppProps } from './App';
// Components
export { Sidebar } from './components/Sidebar';
export { Header } from './components/Header';
// Version
export const version = '1.0.0';
Example for Process app:
export { processPlugin } from './plugin';
export { App as ProcessApp } from './App';
export type { AppProps as ProcessAppProps } from './App';
Step 4: Integrate into Next.js Container
Add Route
Edit packages/flowstate-app-nextjs/src/config/routes.tsx:
// Add lazy import at the top
const <AppName>App = lazy(() => import('@epicdm/flowstate-app-<app-name>').then((m) => ({ default: m.<AppName>App })));
// Add route inside <RoutesComponent>
<RouteComponent
path="/apps/<app-name>/*"
element={<<AppName>App config={{ useHostRouter: true, basePath: '/apps/<app-name>' }} />}
/>
Add Tailwind Content
Edit packages/flowstate-app-nextjs/tailwind.config.js:
content: [
// ... existing paths
'../apps/flowstate-app-<app-name>/src/**/*.{js,jsx,ts,tsx}',
]
Update Next.js Config
Edit packages/flowstate-app-nextjs/next.config.mjs:
// Add to transpilePackages array
'@epicdm/flowstate-app-<app-name>',
// Add to config.resolve.alias object
'@epicdm/flowstate-app-<app-name>$': resolve(__dirname, '../apps/flowstate-app-<app-name>/src/index.ts'),
// Add to config.resolve.modules.push() call
resolve(__dirname, '../apps/flowstate-app-<app-name>/src'),
Add Dependency
Edit packages/flowstate-app-nextjs/package.json:
"dependencies": {
"@epicdm/flowstate-app-<app-name>": "workspace:*"
}
Add Manifest
Edit packages/flowstate-app-nextjs/src/components/providers/ManifestLoader.tsx:
import <appName>Manifest from '../../../../apps/flowstate-app-<app-name>/flowstate.json';
const manifests = [
// ... existing manifests
<appName>Manifest,
] as const;
Step 5: Integrate into Electron Container
Add App Component
Edit packages/flowstate-app-electron/src/renderer/config/apps.ts:
<app-name>: lazy(() =>
import('@epicdm/flowstate-app-<app-name>').then((m) => ({ default: m.<AppName>App }))
),
Add Route
Edit packages/flowstate-app-electron/src/renderer/routes/index.tsx:
// Add variable assignment
const <AppName>App = appComponents.<app-name>;
// Add route inside <Routes>
<Route
path="/apps/<app-name>/*"
element={<<AppName>App config={{ useHostRouter: true, basePath: '/apps/<app-name>' }} />}
/>
Add Tailwind Content
Edit packages/flowstate-app-electron/tailwind.config.js:
content: [
// ... existing paths
'../apps/flowstate-app-<app-name>/src/**/*.{js,jsx,ts,tsx}',
]
Update Vite Config
Edit packages/flowstate-app-electron/vite.config.ts:
// Add to resolve.alias object
'@epicdm/flowstate-app-<app-name>$': path.resolve(__dirname, '../apps/flowstate-app-<app-name>/src/index.ts'),
'@epicdm/flowstate-app-<app-name>': path.resolve(__dirname, '../apps/flowstate-app-<app-name>/src'),
// Add to optimizeDeps.exclude array
'@epicdm/flowstate-app-<app-name>',
// Add to ssr.noExternal array
'@epicdm/flowstate-app-<app-name>',
Add Dependency
Edit packages/flowstate-app-electron/package.json:
"dependencies": {
"@epicdm/flowstate-app-<app-name>": "workspace:*"
}
Add Manifest
Edit packages/flowstate-app-electron/src/renderer/providers/ManifestLoader.tsx:
import <appName>Manifest from '../../../../apps/flowstate-app-<app-name>/flowstate.json';
const manifests = [
// ... existing manifests
<appName>Manifest,
] as const;
Create Type Declaration
Create packages/flowstate-app-electron/src/types/epic-flow__flowstate-app-<app-name>.d.ts:
declare module '@epicdm/flowstate-app-<app-name>' {
import { ComponentType } from 'react';
export const <appName>Plugin: any;
export const <AppName>App: ComponentType<any>;
}
Step 6: Configure Plugin Manifest
Update packages/apps/flowstate-app-<app-name>/flowstate.json:
{
"$schema": "https://flowstate.dev/schemas/plugin-manifest-v1.json",
"id": "<app-name>",
"displayName": "<App Name>",
"version": "1.0.0",
"description": "<App description>",
"publisher": "flowstate",
"main": "./dist/index.js",
"browser": "./dist/index.mjs",
"icon": "<lucide-icon-name>",
"color": "#6366f1",
"route": "/apps/<app-name>",
"order": 50,
"basePath": "/<app-name>",
"category": "technical",
"activationEvents": ["onRoute:/<app-name>"],
"permissions": [],
"requiresServer": false,
"contributes": {
"commands": [],
"menus": [],
"keybindings": []
}
}
Manifest fields:
| Field | Description |
|---|---|
id | Unique app identifier (kebab-case) |
displayName | Human-readable name shown in UI |
icon | Lucide icon name (e.g., "workflow", "folder-kanban") |
color | Hex color for app branding |
order | Sidebar position (lower = higher) |
category | App category: "business", "technical", "other" |
Step 7: Install Dependencies and Build
# Install workspace dependencies
yarn install
# Build the new app
yarn workspace @epicdm/flowstate-app-<app-name> build
# Verify typecheck passes
yarn workspace @epicdm/flowstate-app-<app-name> typecheck
yarn workspace @epicdm/flowstate-app-nextjs typecheck
yarn workspace @epicdm/flowstate-app-electron typecheck
Step 8: Verification
Verify No Boilerplate References Remain
grep -r "Boilerplate\|boilerplate" packages/apps/flowstate-app-<app-name>/
# Should return no matches
Test in Next.js Container
yarn dev:nextjs
Navigate to: http://localhost:4000/apps/<app-name>/home
Verify:
- App loads without errors
- App name displays correctly in header/sidebar
- App appears in launcher grid
- Navigation works correctly
Test HMR (Hot Module Replacement)
- Make a change to a component in the app
- Verify the change appears in the browser without full reload
Troubleshooting
App not appearing in sidebar
- Verify manifest is imported in
ManifestLoader.tsxfor both containers - Check
flowstate.jsonhas validrouteandorderfields - Restart dev server after manifest changes
TypeScript errors after integration
- Run
yarn workspace @epicdm/flowstate-app-<app-name> buildto generate dist files - Verify type declaration file exists for Electron container
- Check all aliases are correctly configured
- If error mentions "Property 'config' does not exist", ensure the type declaration uses
ComponentType<any>
Styles not applying
- Verify content path added to both container
tailwind.config.jsfiles - Restart dev server after Tailwind config changes
HMR not working
- Verify source aliases point to
src/index.ts(notdist/) - Check
optimizeDeps.excludeincludes the app package - Check
ssr.noExternalincludes the app package
Next Steps
Once your app is created and integrated:
- Review Features & Capabilities for template customization
- Check Workflows for detailed step-by-step guides
- See FAQ for answers to common questions