Beszel
Audited from github.com/henrygd/beszel
Beszel is an open-source, lightweight server monitoring tool that tracks CPU, memory, disk, network, Docker, and ZFS metrics with history and alerts through a hub-and-agent architecture.
- Language
- Go
- Database
- SQLite
- Hosting
- Docker
- License
- MIT
- Running for
- 1 year
- Team
- Solo Developer
Why this architecture
Building the hub on PocketBase gives Beszel a REST API, auth, realtime updates, and SQLite storage from one embedded framework, while a separate Go agent binary keeps the footprint on monitored systems minimal, matching its stated goal of being lighter than existing monitoring solutions.
Tech stack by layer
11 technologies · audited Sep 17, 2026- ReactRenders the hub dashboard SPA in internal/site, embedded into the hub Go binary at build time.
- ViteBuilds the site bundle; the Makefile touches internal/site/dist/index.html so hub builds succeed without it.
- Tailwind CSSUtility CSS for the dashboard, using the v4 Vite plugin.
- Radix UIHeadless components (dialog, dropdown, tabs, tooltip, switch) used across the dashboard.
- RechartsRenders CPU, memory, disk, and network history charts on system pages.
- GoImplements both the hub server and the per-system monitoring agent.
- PocketBaseEmbedded backend framework giving the hub its REST API, auth, realtime subscriptions, and admin UI.
- CobraParses CLI commands and flags for the hub and agent binaries.
- SQLitePocketBase-managed embedded database storing systems, metric history, users, and alerts.
- DockerShips multi-arch hub and agent images, including alpine, Intel, and Nvidia GPU variants.
- HelmOfficial Helm chart is built and version-bumped by CI on release.
- GoReleaserCross-compiles and packages hub/agent release binaries for multiple OS/arch targets.
Beszel architecture diagram
Open SVGDiagram as text
- Dashboard (React · Recharts) → Beszel hub (Go · PocketBase): REST · realtime
- Agents (Go · per system) → Beszel hub (Go · PocketBase): WebSocket / SSH
- Beszel hub (Go · PocketBase) → SQLite (systems · metrics · alerts): PocketBase
- Beszel hub (Go · PocketBase) → Notifications (multi-provider): alerts
- Agents (Go · per system) → Monitored systems (CPU · disk · GPU): collect
Key architectural decisions
8 decisions- 01
Hub and agent are separate Go binaries in one repository
internal/cmd/hub and internal/cmd/agent (referenced from the Makefile build-hub/build-agent targets) build independently: the hub is the dashboard/collector, and the agent runs on each monitored system, communicating metrics back to the hub.
- 02
PocketBase is the entire backend, not just a database wrapper
go.mod depends directly on github.com/pocketbase/pocketbase, which supplies the hub REST API, authentication (including OAuth2/OIDC per the README), realtime record subscriptions, and the embedded SQLite storage, avoiding a hand-built API layer.
- 03
The dashboard is a React SPA embedded into the hub binary
internal/site/package.json defines a Vite/React build; the Makefile build-web-ui target compiles it before build-hub, and build-hub-dev stubs internal/site/dist/index.html so the Go binary still compiles without a prior frontend build.
- 04
SQLite runs without cgo via a pure-Go driver
go.mod pulls in modernc.org/sqlite as an indirect dependency of PocketBase, letting the hub ship as a single static binary (per the -ldflags "-w -s" Makefile build flags) without a C toolchain at runtime.
- 05
Agent-hub link uses a lightweight websocket client with optional SSH setup
go.mod includes github.com/lxzan/gws for websocket connections and github.com/gliderlabs/ssh; the agent/ directory has dedicated connection_manager.go and client.go files handling this link, matching the READMEs description of the agent reporting metrics to the hub.
- 06
Notifications are delegated to a multi-provider library, not custom integrations
go.mod depends on github.com/nicholas-fedor/shoutrrr, which the alerts system (internal/alerts) uses to send alerts through many third-party notification services from one abstraction.
- 07
GPU and hardware-sensor support is compiled conditionally per platform
The agent/ directory has OS- and vendor-specific files (gpu_nvml_linux.go, gpu_amd_linux.go, gpu_intel_sysfs_linux.go, sensors_windows.go, fans_linux.go), and the Makefile HOST_GLIBC/AGENT_GO_TAGS logic enables NVML GPU support only on compatible glibc Linux hosts.
- 08
Release automation covers binaries, Docker images, and a Helm chart from one pipeline
The .github/workflows directory has release.yml, docker-images.yml, helm-charts.yml, and update-helm-charts.yml, plus a .goreleaser.yml, so a single tagged release produces GitHub release binaries, container images, and an updated chart.
How Beszel is built
How Beszel is structured
Beszel splits into two independently built Go binaries from one repository: the hub, which runs the dashboard and stores data, and the agent, which runs on each monitored system and reports metrics back. The Makefile exposes separate build-hub and build-agent targets, and the internal/ directory holds hub-side code (internal/hub, internal/entities, internal/records, internal/migrations, internal/alerts, internal/site for the dashboard), while agent/ holds all the platform-specific metric collection code (CPU, disk, GPU, sensors, Docker, ZFS, S.M.A.R.T.).
Frontend
The dashboard is a React and TypeScript single-page app under internal/site, built with Vite 7 and styled with Tailwind CSS v4 via @tailwindcss/vite. UI primitives come from Radix UI (@radix-ui/react-dialog, -dropdown-menu, -tabs, -tooltip, -switch, and others), state is managed with nanostores and @nanostores/react, and charts (CPU, memory, disk, network history) use Recharts. Internationalization runs through Lingui (@lingui/react, @lingui/cli), with a generate-locales Makefile step that extracts and compiles translations before a build if none exist yet. The site is a normal Vite app in development (vite --host) but is compiled to static assets and embedded into the hub Go binary for production, so the hub ships as a single executable.
Backend & APIs
The hub is not a hand-rolled API server: go.mod depends directly on github.com/pocketbase/pocketbase, an embeddable Go backend framework that supplies the REST API, record-based data model, authentication (including OAuth2/OIDC, per the project README), realtime subscriptions, and an admin UI out of the box. Beszel's own Go code in internal/hub, internal/records, and internal/migrations extends PocketBase with its monitoring-specific collections and business logic rather than replacing its HTTP layer. CLI behavior for both hub and agent is handled by github.com/spf13/cobra (with spf13/pflag and spf13/cast as supporting flag/parsing libraries).
Data & persistence
Because the hub is built on PocketBase, its persistence layer is SQLite, reached through the pure-Go modernc.org/sqlite driver (an indirect dependency in go.mod), which avoids requiring cgo or a system SQLite library at build or run time. This keeps the hub deployable as a single static binary. The agent itself is stateless between restarts beyond local caching handled by agent/agent_cache.go and the agent/deltatracker package, which tracks deltas (for example cumulative disk/network counters) between metric collection intervals before sending values to the hub.
Realtime / collaboration
Agents connect outward to the hub over a websocket client built on github.com/lxzan/gws, managed from agent/connection_manager.go and agent/client.go. The hub side, via PocketBase's realtime record subscriptions, pushes updated metrics to connected dashboard clients without a manual polling loop. github.com/gliderlabs/ssh is also a direct dependency, used in the hub/agent pairing flow described in the project's fingerprint-based agent authentication (agent/fingerprint.go, internal/hub).
Build, test & deploy
CI is GitHub Actions-based: docker-images.yml builds and pushes multi-arch Docker images, release.yml and .goreleaser.yml drive binary releases, helm-charts.yml and update-helm-charts.yml keep the published Helm chart in sync with releases, and vulncheck.yml runs Go vulnerability scanning. Go tests run with build tags (go test -tags='testing no_ui' ./... in the Makefile), and there are extensive platform-specific _test.go files alongside the platform-specific source files (for example agent/gpu_nvml_linux.go and agent/gpu_nvml_linux_test.go). The internal/dockerfile_agent* files define separate Dockerfiles for the standard, alpine, Intel, Nvidia, and Nvidia-slim agent images.
Self-hosting notes
Beszel is explicitly built for self-hosting: the hub and agent are each published as Docker images (internal/dockerfile_hub, internal/dockerfile_agent*), a Helm chart is maintained under supplemental/helm and published via CI, and a Debian package build lives under supplemental/debian. GPU monitoring support (Nvidia via NVML, AMD, Intel) is conditionally compiled based on the target platform, as seen in the Makefile's HOST_GLIBC/AGENT_GO_TAGS detection logic and the per-vendor agent/gpu_*.go files.
What to copy (and what not to)
Embedding PocketBase to get a full backend (API, auth, realtime, SQLite) instead of assembling a framework, an ORM, and a realtime layer separately is a strong pattern for small, self-hostable tools that need to stay a single binary. Compiling the frontend to static assets and embedding it into the Go binary, with a Makefile fallback that stubs dist/index.html for hub-only development builds, is a clean way to avoid forcing every contributor to run a JS toolchain. The heavy use of platform-specific Go build tags for GPU and sensor support (agent/gpu_nvml_linux.go vs agent/gpu_nvml_unsupported.go) is worth studying for any Go project that needs to gracefully degrade across OS/hardware combinations, though it does mean the agent's test matrix grows with every new platform variant.
Sources & repo audit
- Go module dependencies (PocketBase, Cobra, gws, shoutrrr, SQLite)
- Build orchestration for hub, agent, and web UI
- Dashboard frontend dependencies (React, Vite, Tailwind, Radix, Recharts)
- Release workflow
- Helm chart CI workflow
Independent analysis of repository at github.com/henrygd/beszel. Spotted an inaccuracy? Use the claim form to request a correction.
Show this stack on your README or website
[](https://stackitfast.com/project/beszel)Paste it into your README. It shows your current stack and links to this page.
Scaffold it with your agent
Paste this prompt into Claude Code, Cursor, Windsurf or AGY to start a project with Beszel's architecture.
- 1Copy the promptThe full markdown spec, with every layer and decision.
- 2Open your AI toolClaude Code, Cursor, Windsurf or Copilot, in a new repo.
- 3Paste and scaffoldUse it as the first instruction; review before you ship.
# MISSION: Scaffold "Beszel" Production Architecture
You are an expert Senior Staff Software Architect and Full-Stack Engineer. Your mission is to scaffold and implement a production-grade, highly reliable, and modular codebase following the proven architecture of **Beszel**.
---
## 1. PROJECT SPECIFICATIONS & BENCHMARK
- **Reference Architecture**: Beszel
- **What It Does**: Beszel is an open-source, lightweight server monitoring tool that tracks CPU, memory, disk, network, Docker, and ZFS metrics with history and alerts through a hub-and-agent architecture.
- **Domain & Category**: Lightweight Server & Container Monitoring
- **Production Scale**: Solo Developer
- **Development Mode**: CLASSIC
- **Architectural Rationale**: Building the hub on PocketBase gives Beszel a REST API, auth, realtime updates, and SQLite storage from one embedded framework, while a separate Go agent binary keeps the footprint on monitored systems minimal, matching its stated goal of being lighter than existing monitoring solutions.
- **Live Website Reference**: https://beszel.dev
- **Source Repository**: https://github.com/henrygd/beszel
---
## 2. PRODUCTION TECH STACK
- **Full Stack Array**: Go, PocketBase, SQLite, React, TypeScript, Vite, Tailwind CSS, Radix UI, Recharts, Docker, Helm
- **Primary Language(s)**: Go, TypeScript
- **License of the reference repo**: MIT
- **Frontend**: React — Renders the hub dashboard SPA in internal/site, embedded into the hub Go binary at build time.; Vite — Builds the site bundle; the Makefile touches internal/site/dist/index.html so hub builds succeed without it.; Tailwind CSS — Utility CSS for the dashboard, using the v4 Vite plugin.; Radix UI — Headless components (dialog, dropdown, tabs, tooltip, switch) used across the dashboard.; Recharts — Renders CPU, memory, disk, and network history charts on system pages.
- **Backend & APIs**: Go — Implements both the hub server and the per-system monitoring agent.; PocketBase — Embedded backend framework giving the hub its REST API, auth, realtime subscriptions, and admin UI.; Cobra — Parses CLI commands and flags for the hub and agent binaries.
- **Data & persistence**: SQLite — PocketBase-managed embedded database storing systems, metric history, users, and alerts.
- **Infrastructure & deploy**: Docker — Ships multi-arch hub and agent images, including alpine, Intel, and Nvidia GPU variants.; Helm — Official Helm chart is built and version-bumped by CI on release.; GoReleaser — Cross-compiles and packages hub/agent release binaries for multiple OS/arch targets.
---
## 3. KEY ARCHITECTURAL DECISIONS (audited from https://github.com/henrygd/beszel @ 18f7a4b)
1. **Hub and agent are separate Go binaries in one repository**: internal/cmd/hub and internal/cmd/agent (referenced from the Makefile build-hub/build-agent targets) build independently: the hub is the dashboard/collector, and the agent runs on each monitored system, communicating metrics back to the hub.
2. **PocketBase is the entire backend, not just a database wrapper**: go.mod depends directly on github.com/pocketbase/pocketbase, which supplies the hub REST API, authentication (including OAuth2/OIDC per the README), realtime record subscriptions, and the embedded SQLite storage, avoiding a hand-built API layer.
3. **The dashboard is a React SPA embedded into the hub binary**: internal/site/package.json defines a Vite/React build; the Makefile build-web-ui target compiles it before build-hub, and build-hub-dev stubs internal/site/dist/index.html so the Go binary still compiles without a prior frontend build.
4. **SQLite runs without cgo via a pure-Go driver**: go.mod pulls in modernc.org/sqlite as an indirect dependency of PocketBase, letting the hub ship as a single static binary (per the -ldflags "-w -s" Makefile build flags) without a C toolchain at runtime.
5. **Agent-hub link uses a lightweight websocket client with optional SSH setup**: go.mod includes github.com/lxzan/gws for websocket connections and github.com/gliderlabs/ssh; the agent/ directory has dedicated connection_manager.go and client.go files handling this link, matching the READMEs description of the agent reporting metrics to the hub.
6. **Notifications are delegated to a multi-provider library, not custom integrations**: go.mod depends on github.com/nicholas-fedor/shoutrrr, which the alerts system (internal/alerts) uses to send alerts through many third-party notification services from one abstraction.
7. **GPU and hardware-sensor support is compiled conditionally per platform**: The agent/ directory has OS- and vendor-specific files (gpu_nvml_linux.go, gpu_amd_linux.go, gpu_intel_sysfs_linux.go, sensors_windows.go, fans_linux.go), and the Makefile HOST_GLIBC/AGENT_GO_TAGS logic enables NVML GPU support only on compatible glibc Linux hosts.
8. **Release automation covers binaries, Docker images, and a Helm chart from one pipeline**: The .github/workflows directory has release.yml, docker-images.yml, helm-charts.yml, and update-helm-charts.yml, plus a .goreleaser.yml, so a single tagged release produces GitHub release binaries, container images, and an updated chart.
---
## 4. NON-NEGOTIABLE ARCHITECTURAL GUARDRAILS
1. **Monorepo & Modular Separation**:
- Structure as a Turborepo monorepo with strict package boundaries:
- `apps/web`: Application UI, routing, layouts, and server endpoints.
- `packages/ui`: Shared design tokens, CSS variables, and Radix UI primitive components.
- `packages/db`: Database schemas, client singleton, declarative migrations, and seed scripts.
- `packages/config`: Shared TypeScript, ESLint, and build configurations.
2. **Strict Type Safety & Zero `any` Policy**:
- Enable `strict: true`, `noImplicitAny: true`, and `strictNullChecks: true`.
- Validate ALL external inputs, API request bodies, and query parameters with **Zod** schemas before execution.
3. **Frontend & Rendering Guidelines**:
- Utilize Vite 6 with TanStack Router for fully type-safe routing. Manage server state and caching via TanStack Query v5 with optimistic UI updates.
4. **Design System & Aesthetics**:
- Keep every color, radius, shadow and font in a single token file (CSS variables) and consume tokens everywhere; never hardcode hex values in components.
- Prefer crisp 1px borders and one subtle shadow scale over blurry default shadows. Pair one sans-serif for body/headings with one monospace for tags, badges, metrics, and code.
5. **Data Layer & Reliability**:
- Write declarative schema definitions with foreign keys, composite indexes on queried filters, and automated timestamp triggers.
- Use connection pooling and prepared statements for serverless database execution.
---
## 5. STEP-BY-STEP SCAFFOLDING ROADMAP
- **Phase 1: Workspace & Root Config**: Initialize package manager, monorepo configuration (`turbo.json`, `tsconfig.base.json`, `package.json`).
- **Phase 2: Database Schema & Client**: Set up the data layer (SQLite): client, connection pool, models, and migration scripts.
- **Phase 3: Design Tokens & UI Primitives**: Build accessible `Button`, `Input`, `Card`, `Badge`, and layout wrappers inside `packages/ui`.
- **Phase 4: Core Application Routes & Handlers**: Implement primary authentication, user session handling, and application routes.
- **Phase 5: Quality Assurance & Build Verification**: Run `tsc --noEmit`, ESLint, Prettier, and smoke test suites to ensure zero compilation or runtime errors.
---
## 6. EXECUTION INSTRUCTIONS
1. Review all specifications, architectural guardrails, and stack choices above.
2. Present the full monorepo directory tree structure.
3. Systematically generate the complete, production-ready codebase according to the 5-phase roadmap above — starting with the root workspace setup, followed by the database schema, UI design system package, and full-stack application routes until the repository is fully scaffolded and ready to run.Frequently asked about Beszel
What is Beszel built with?
Beszel is written in Go for both the hub and monitoring agent. The hub embeds PocketBase for its API, auth, and SQLite storage, and serves a React and TypeScript dashboard built with Vite, Tailwind CSS, and Radix UI.
Does Beszel need an external database?
No. The hub uses PocketBase, which stores everything in an embedded SQLite database via the pure-Go modernc.org/sqlite driver, so there is no separate database server to run.
Can I self-host Beszel?
Yes. Beszel ships multi-arch Docker images for the hub and agent (including Nvidia GPU variants), a Helm chart for Kubernetes, and prebuilt release binaries produced by GoReleaser.
How does the Beszel agent send data to the hub?
The agent, a separate Go binary that runs on each monitored system, connects to the hub over a lightweight websocket client (github.com/lxzan/gws) managed by code in the agent/ directory such as connection_manager.go.
One email a month: new deep dives and stack trends
New source-audited architectures, head-to-head comparisons and the monthly stack report. No spam, unsubscribe anytime.
Similar architectures
- OllamaAI-agentLocal AI Inference Engine · 1-5 peopleShares Go · TypeScript · React
- GatusClassicAutomated Health Dashboard & Status Monitor · soloShares Go · SQLite · Tailwind CSS
- GrafanaClassicMonitoring & Observability Dashboard · 20+ peopleShares TypeScript · Go · React
- PocketBaseClassicEmbedded Backend · SoloShares Go · SQLite · Vite
- Fasten HealthClassicPersonal Health Records & Medical EHR Engine · Solo DeveloperShares Go · TypeScript · SQLite
- HasuraClassicInstant GraphQL Engine & Unified Data Access · 20+ peopleShares TypeScript · Go · React