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
lunx createwrites a ready-to-install project from one of 26 templates: React, Vue, Svelte, Solid, Preact, Lit, Alpine, Angular, Qwik and vanilla apps, the meta-frameworks (Next.js, Nuxt, SvelteKit, Astro, React Router, TanStack Start, SolidStart, Qwik City, VitePress, Waku, Analog, Remix, Docusaurus, Marko Run), a library and an edge function. Each template is installed, built and opened in a browser by lunx's template test (npm run test:templates).
# Interactive: pick a template, TypeScript or JavaScript, Tailwind npx lunx-dev@latest create my-app # Non-interactive for React + TypeScript + Tailwind npx lunx-dev@latest create my-app --template 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-dev' 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, // Oxc + 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
Boots in about 300 ms, Node startup included. A saved file reaches the browser in about 50 ms on a small app, with component state 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, recompiles only the changed module with Oxc, 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