Project Structure
- index.tsApp lifecycle
- window.tsMain, activation and About windows
- menu.tsNative menu
- updater.tsAuto updater
- events.tsTyped event bus, forwarded to the renderer
- paths.tsPaths of resources/ and drizzle/ in dev and production
- index.tsExposes tRPC to the renderer, nothing else
- config.tsConfig schema
- i18n.tsTranslation resources
- license.tsLicense types and helpers
- index.html
- main.tsxEntry point
- styles.cssTailwind CSS and theme colors
- AGENTS.mdInstructions for AI agents (CLAUDE.md imports it)
- biome.jsonLinter and formatter
- components.jsonshadcn/ui
- drizzle.config.tsdrizzle-kit
- electron-builder.tsPackaging, signing, publishing
- electron.vite.config.tsBuild of main, preload and renderer
- tsconfig.node.jsonMain + preload (Node.js types)
- tsconfig.web.jsonRenderer (DOM types)
Processes
Electron apps run code in several processes:
- Main – runs in Node.js, creates windows and has full system access. It owns the database, the config file and the auto updater.
- Preload – runs before the page loads. In this template it only exposes the tRPC bridge.
- Renderer – runs your React UI in a sandboxed Chromium page, without access to Node.js. It talks to the main process only through tRPC.
Code needed by both sides (zod schemas, types, translations) lives in
src/shared/.
Import aliases
| Alias | Points to | Available in |
|---|---|---|
@renderer/* | src/renderer/src/ | Renderer |
@shared/* | src/shared/ | Main, preload, renderer |
@main/* | src/main/ | Renderer, types only |
The renderer imports the type of the tRPC router from @main/trpc/router, which
is why tsconfig.web.json also includes src/main. Importing a value from
@main in the renderer would fail at runtime.
Last updated on