Create a project
Create a Shellui project with the CLI, start the host, and build static files to dist/web/. You need Node.js 18+ and a working CLI install of Shellui 0.6.0.
Scaffold with shellui init
From an empty directory (or a folder you want the CLI to fill):
mkdir my-shellui-app
cd my-shellui-app
shellui init
The wizard asks for a framework and a backend. Shortcuts skip the framework prompt:
shellui init react
shellui init empty
shellui init --framework next --backend none
init writes shellui.config.json (with $schema for editor autocomplete), placeholder files under static/, and - for JS frameworks - a companion app plus dev.run / dev.url so shellui start launches both. Overwrite an existing config with shellui init --force. Skip npm/pnpm install after a JS scaffold with --no-install.
Frameworks: empty, react, vue, angular, next, nuxt, svelte, alpine. Each JS starter wires theme and i18n with @shellui/sdk/tiny using that stack's normal patterns (hooks, composables, services, plugins). See Framework starters for ports and per-framework notes, or CLI init for flags.
If you still have a TypeScript config from an older project, convert it with shellui config migrate.
Write the config by hand
Prefer shellui init. To start from JSON only:
{
"$schema": "./node_modules/@shellui/core/schemas/shellui.config.schema.json",
"port": 4000,
"title": "My Shellui App",
"backend": {
"type": "supabase",
"url": "http://localhost:54321"
},
"navigation": [
{
"label": "Home",
"path": "home",
"url": "http://localhost:4000/",
"icon": "/icons/home.svg"
}
]
}
init defaults the shell to port 4000. If port is omitted, shellui start falls back to 3000. String values may use ${VAR} or ${VAR:-default} - see environment substitution. Store config outside the project root with --config or SHELLUI_CONFIG.
Put favicon.svg, logo.svg, and icons under static/ (for example static/icons/home.svg). The CLI serves that folder.
Start the development server
shellui start
Local install:
npx shellui start
shellui dev is the same command. The CLI starts Vite for @shellui/core, opens the browser on first start, watches config files, and prints the local URL. Listen on the LAN with shellui start --host. Open a native window with shellui start --app - see Desktop app.
Typical terminal output:
Starting Shellui...
Loaded JSON config from /path/to/shellui.config.json
👀 Watching config file: /path/to/shellui.config.json
VITE v7.x.x ready in 123 ms
➜ Local: http://localhost:4000/
➜ Network: use --host to expose
Build for production
shellui build
The CLI resolves ${ENV} placeholders at build time, embeds a frozen config in the bundle, writes dist/web/shellui.config.json (resolved values only), and emits a static site under dist/web/. That snapshot is public - do not put secrets in config. Changing env vars after the build has no effect until you rebuild.
Shell plus an iframe app
The CLI builds the shell only. Your microfrontend is a normal app (Vite, Next.js, and so on). Both can share one package.json.
The playground uses that pattern: Shellui CLI for the host, Vite for the iframe. One pnpm start runs both because config includes:
{
"dev": {
"run": "vite",
"url": "http://localhost:5173"
}
}
{
"scripts": {
"start": "shellui start",
"start:app": "vite",
"build": "shellui build && vite build"
}
}
start:app is an escape hatch. shellui start --shell-only ignores dev.run. Flags --run and --follow override dev. See companion process.
shellui start and shellui build do not load your vite.config.*, PostCSS, tsconfig.json, or VITE_*. Tailwind for the shell scans @shellui/core only. The shell Vite cache is node_modules/.vite-shellui. See tooling isolation.
Point navigation urls at the companion origin in development (for example http://localhost:5173/#/) and at the built path in production. From 0.5.1, set safeForAuthToken: true on items whose companion needs settings.accessToken. See Authentication, iframe apps. Call @shellui/sdk inside the iframe.
Typical tree:
my-shellui-app/
├── shellui.config.json
├── package.json
├── static/
├── dist/
│ ├── web/
│ └── app/
└── node_modules/
dist/ is generated and gitignored.
Troubleshoot a failed start
Port in use. Set another port in config:
{
"port": 5000
}
Config not loading. Keep shellui.config.json in the project root (or pass --config). Validate JSON against $schema. JSON and split shellui.*.config.json files cannot coexist. TypeScript config is used only when no JSON or split files exist.
Build errors. Run npm install (or pnpm install), then re-read the CLI error. Invalid config fails at load time with schema messages.
Next steps
- Framework starters - ports, theme/i18n wiring, and per-framework notes
- Backend - identity-service, Supabase, or a public shell
- Authentication - login routes and guards
- Navigation - iframe URLs and opening modes
- CLI - full command and config reference
- Desktop app - native window with
--app