Skip to content

Architecture

Home Lab is a single container that serves both a JSON API and a static front-end from the same origin.

Components

ComponentRole
Express 5 (Node.js)REST API + static file serving
better-sqlite3Embedded SQLite database (WAL mode)
React (via Babel)Front-end, transpiled in the browser
docker-socket-proxyOptional sidecar for container status & controls

Data model

Everything lives in one SQLite database under DATA_DIR:

TableHolds
configSingletons: pages, favourites, weather, dashboard, docker config, health source
servicesOne row per card (layout + non-secret config)
credentialsOne row per widget's secrets (API keys, passwords, tokens)

State is loaded into memory on boot and persisted back transactionally on change. On first run it migrates from any legacy JSON files if present.

Request flow

  1. The browser loads the static app and asks the backend for its configuration.
  2. The backend is authoritative - it returns pages, services and non-secret widget config. Secrets are never sent to the browser.
  3. For each widget, the browser polls a per-service endpoint on the widget's refresh interval.
  4. The backend resolves the widget type to an integration, calls the upstream service with the stored credentials, caches the result briefly, and returns it.

Secrets

  • API keys, passwords and tokens are stored only in the credentials table.
  • The public config returned to the browser contains only non-secret keys.
  • Backups do include secrets (in plaintext) because a restore needs them - see Backups.

Docker control

Home Lab never opens the Docker socket itself. A docker-socket-proxy sidecar exposes a narrow, mostly read-only slice of the Docker API; Home Lab talks to that over HTTP to show container status and issue start/stop/restart.

Persistence & backups

  • The database and the backups/ folder both live under the persisted DATA_DIR volume.
  • A daily backup of the whole dataset is written and pruned to the last 7.

Front-end notes

  • The app applies the saved theme before rendering (no flash on reload).
  • It uses a network-first service worker for an installable, offline-capable shell - see PWA.
  • A dedicated mobile layout turns the sidebar into a drawer below 760 px - see Mobile.

Next steps