mit einem Klick
desktop
// Use for any desktop app task — planning, designing, implementing pages, components, API routes, and building.
// Use for any desktop app task — planning, designing, implementing pages, components, API routes, and building.
| name | desktop |
| description | Use for any desktop app task — planning, designing, implementing pages, components, API routes, and building. |
Electron + Vite + React frontend with a standalone Hono API server running on Bun.
| Layer | Tech | Location |
|---|---|---|
| Shell | Electron | packages/app/electron/ |
| Frontend | React + Vite + TanStack Query | packages/app/src/ |
| API | Hono (Bun) | packages/api/src/ |
| Database | SQLite via bun:sqlite + Drizzle ORM | packages/api/src/database/ |
| RPC | hono/client | packages/app/src/lib/api.ts |
.env ← all env vars (VITE_ = shared, rest = API-only)
packages/
api/
src/
index.ts ← Hono app, exports AppType, serves on port 3001
database/
index.ts ← drizzle + bun:sqlite (data/app.db, WAL mode)
schema.ts ← Drizzle table definitions
drizzle/ ← Generated SQL migrations
drizzle.config.ts ← Drizzle-kit config
package.json
app/
electron/
main.ts ← Electron main process
preload.ts ← Preload script
src/
main.tsx ← React entry, QueryClientProvider
App.tsx ← Root component
lib/
api.ts ← hc<AppType>(import.meta.env.VITE_API_URL)
index.css
index.html
vite.config.ts ← aliases @runable/api → ../api
package.json
All env vars live in a single .env file at the project root.
| Prefix | Available to | How to access |
|---|---|---|
VITE_ | Desktop app (renderer) and API server | App: import.meta.env.VITE_* · API: process.env.VITE_* |
| No prefix | API server only | process.env.* (Bun auto-loads .env) |
The desktop app (Vite/Electron renderer) cannot see non-prefixed vars — Vite strips them at build time. Use this to keep secrets (DB credentials, auth secrets, API keys) out of the frontend.
Example .env:
# API-only (secret, never exposed to renderer)
BETTER_AUTH_SECRET=supersecretkey
DATABASE_URL=data/app.db
# Shared (available to both app and API)
VITE_API_URL=http://localhost:3001
# Run everything (API + Electron app)
bun run dev
# Run individually
bun run dev:api # Hono server on :3001 with --hot
bun run dev:app # Vite + Electron
Schema lives in packages/api/src/database/schema.ts. After changing it:
cd packages/api
bun run db:generate # Generate migration SQL
bun run db:migrate # Apply migrations
bun run db:studio # Browse data in Drizzle Studio
The SQLite database file is at packages/api/data/app.db (gitignored).
The API uses Hono with chained routes. The app consumes it via typed RPC client.
Adding a route in packages/api/src/index.ts:
const app = new Hono()
.use("/*", cors())
.get("/ping", (c) => c.json({ message: "pong" }))
.get("/users", async (c) => {
const result = await database.select().from(users);
return c.json(result);
});
export type AppType = typeof app;
Consuming from the app in packages/app/src/:
const res = await api.users.$get();
const data = await res.json();
bun run build # Vite build only
bun run build:mac # macOS (dmg + zip, x64 + arm64)
bun run build:win # Windows (nsis, x64)
bun run build:linux # Linux (AppImage + deb, x64)
bun run build:all # All platforms