Quick Start Guide
Bootstrap a new application from zero to running dev server in under 2 minutes. This guide walks through project setup, directory structure, and the full dev-to-production workflow.
1. Bootstrap with lunx create
The lunx create CLI generator provides zero-config templates for all 19 supported frameworks. It detects your Node version, installs dependencies, and writes a minimal config file automatically.
# Interactive — picks framework, TypeScript, CSS for you npm create lunx-dev@latest my-app # Non-interactive for React + TypeScript + Tailwind npm create lunx-dev@latest my-app -- --framework react --ts --tailwind cd my-app && npm install
lunx.config.ts is typically 3–5 lines.2. Project structure
A fresh Lunx project is intentionally minimal. All framework-specific wiring is handled inside the adapter — not inside your project files.
my-app/ ├── src/ │ ├── main.tsx # Application entry point │ ├── App.tsx # Root component │ └── index.css # Global styles / Tailwind input ├── index.html # HTML entry template ├── lunx.config.ts # Minimal Lunx configuration ├── tsconfig.json # TypeScript config (auto-generated) ├── package.json └── .gitignore
3. Understanding lunx.config.ts
The config uses defineConfig for full TypeScript autocomplete. Most fields have sensible defaults — you only declare what differs from the standard behavior.
import { defineConfig } from 'lunx' export default defineConfig({ // Required: which framework adapter to use framework: 'react', // Optional overrides (all have sensible defaults) server: { port: 5173, // default dev port host: true, // expose to local network open: true, // open browser on start }, build: { outDir: 'dist', // output directory minify: true, // SWC + LightningCSS minification sourcemap: false, // enable for debugging production }, security: { scanSecrets: true, // scan before every build checkCVEs: true, // query OSV database for vulnerabilities generateSBOM: true, // CycloneDX 1.5 JSON/XML output sri: true, // inject SHA-384 hashes into index.html }, })
4. Development workflow
Powered by uWebSockets.js and rust-notify. Cold boot in ~36ms. File changes trigger HMR in ~18ms p99 — component state is preserved across module updates.
npm run dev ⚡ lunx v1.0.0 adapter: react port: 5173 Local: http://localhost:5173 Network: http://192.168.1.100:5173 ✓ ready in 36ms
Edit any source file. Lunx detects the change via rust-notify in ~6ms, recompiles only the changed module via SWC, and pushes the delta to your browser over WebSocket. No full page reload.
# After editing src/App.tsx: [hmr] module updated: src/App.tsx (18ms) [hmr] 1 component reloaded — state preserved
Lunx runs the 8-stage security pipeline before bundling. Any violation aborts the build. Output is minified, content-hashed, and SRI-protected.
npm run build 🔍 Security scan... ✓ Secrets: 0 found across 84 files ✓ CVEs: 0 critical, 0 high in 312 packages ✓ SBOM: dist/bom.json written (CycloneDX 1.5) ✓ SRI: SHA-384 hashes injected into index.html 📦 dist/ assets/main-cf861a.js 94.2 kB │ gzip: 30.1 kB assets/style-d31e9a.css 12.4 kB │ gzip: 3.6 kB index.html 0.9 kB ✓ built in 512ms
Run a local preview of your production build to verify asset paths, service worker behavior, and confirm SRI hashes before pushing to production.
npm run preview ⚡ serving dist/ → http://localhost:4173
5. Adding your first component
Lunx supports all standard React patterns — no special wrappers required. Create a component, import it, and HMR updates it instantly with state preserved.
import { useState } from 'react' export function Counter() { const [count, setCount] = useState(0) return ( <div className="flex flex-col items-center gap-4 p-8"> <h2 className="text-2xl font-bold tabular-nums">Count: {count}</h2> <div className="flex gap-3"> <button onClick={() => setCount(c => c - 1)} className="px-4 py-2 rounded-lg border border-zinc-700 hover:bg-zinc-800" > Decrement </button> <button onClick={() => setCount(c => c + 1)} className="px-4 py-2 rounded-lg bg-blue-600 text-white hover:bg-blue-700" > Increment </button> </div> </div> ) }
@/ as an alias to your src/ directory. Import using import { Counter } from '@/components/Counter' anywhere in your project.6. Environment variables
Lunx uses .env files following the Vite convention. Only variables prefixed with LUNX_PUBLIC_ are exposed to the browser bundle — all others remain server-side only, preventing accidental secret leaks.
# Browser-safe (exposed to client bundle) LUNX_PUBLIC_API_URL=https://api.example.com LUNX_PUBLIC_APP_NAME=My App # Server-only (never exposed to client) DATABASE_URL=postgres://user:pass@localhost/db STRIPE_SECRET_KEY=sk_live_...
// Access in your components const apiUrl = import.meta.env.LUNX_PUBLIC_API_URL