Architecture
How Rustrak is designed and why.
Overview
┌─────────────────┐ ┌──────────────────────────┐ ┌──────────────────┐
│ Sentry SDK │────▶│ Rustrak server │────▶│ SQLite (default) │
│ (your app) │ │ (Rust / Actix-web) │ │ or PostgreSQL │
└─────────────────┘ │ │ └──────────────────┘
│ /api ingest and API │
┌─────────────────┐ │ / dashboard │
│ Browser │────▶│ (static files) │
└─────────────────┘ └──────────────────────────┘One process in one container answers everything: SDKs send events to /api,
and people open the dashboard at / on the same port. The image is about
20 MB and the server idles under 100 MB of memory.
Key design decisions
One process, one origin
The dashboard is a React application (Vite and TanStack Router) compiled to
static files and built into the server image. The same Actix process that
answers /api/projects hands out /, so:
- There is one container, one port and one address to configure (
PUBLIC_URL) - The browser calls the API on the origin it loaded the page from, so the session cookie is first-party and the dashboard needs no CORS
- The dashboard costs nothing at runtime: the server reads the files once at startup
- Paths under
/api,/auth,/health,/docsand/api-docsalways get an API answer, never the dashboard page
The dashboard stays optional. RUSTRAK_DASHBOARD=off makes the server
API-only, and a server built without a dashboard (a plain cargo build) serves
the API and nothing else.
Two-phase ingestion
Events go through two phases:
SDK → Server → Temp Storage → [Background] → Database
│
└→ Return 200 OK (<50ms)- Ingest (sync): Receive, validate, store temporarily, return 200
- Digest (async): Calculate grouping, create/update issue, store event
Your apps get a fast response while the heavy processing happens in the background. An event accepted by ingest is kept on disk until its digest has committed, so a restart does not lose it.
Sentry protocol compatibility
Rustrak implements the Sentry envelope protocol:
- Use any official Sentry SDK
- No custom SDK to maintain
- Point your DSN at Rustrak
Components
Server (Rust)
Responsibilities:
- Receive events, transactions, spans, sessions and logs from SDKs
- Group errors into issues
- Apply source maps to JavaScript stack traces
- Store data in SQLite or PostgreSQL
- Provide the REST API
- Serve the dashboard
- Send alerts
- Enforce rate limits
Tech: Rust, Actix-web, SQLx, Tokio
Database
SQLite by default, stored at /data/rustrak.db, or PostgreSQL with the
postgres image. The main tables:
projects: project configurationissuesandgroupings: grouped errors and their grouping keysevents: individual error eventstransactions,spans,logs,releases,session_counts: performance, logs and release healthusers,auth_tokens,project_members: accounts and accessalert_rules,alert_integrations,alert_history: alerting
Uploaded source maps are files on disk under SOURCEMAP_STORAGE_PATH
(default /data/sourcemaps), inside the same /data volume as SQLite.
Dashboard
A React single-page application in apps/dashboard, compiled into the server
image:
- Projects, issues and events (stack traces, breadcrumbs, context)
- Performance, releases, logs and AI agent traces
- Alerts, team, tokens and storage settings
Authentication
| Method | Use case | How |
|---|---|---|
| Session | Dashboard | Sign in at /login → httpOnly cookie |
| Bearer Token | API access | Authorization: Bearer <token> |
| SentryAuth | SDK ingestion | DSN sentry_key |
Deployment options
Default: one container
SDKs and browsers → Server (API + dashboard) → SQLite or PostgreSQLThe setup the installation guide describes. Put a reverse proxy in front for HTTPS; it has one upstream.
API only
SDKs and scripts → Server (API) → SQLite or PostgreSQLSet RUSTRAK_DASHBOARD=off. The server serves no pages.
Dashboard on its own host
SDKs → Server (API, RUSTRAK_DASHBOARD=off) → Database
▲
│ /api, /auth, /health, /docs, /api-docs
│
Browser → rustrak-ui (nginx + dashboard) on another hostFor keeping the machine that holds your data free of any frontend.
rustrak/rustrak-ui serves the same dashboard and proxies the API paths to
RUSTRAK_API_URL, so the browser still sees one origin. Set DASHBOARD_URL
on the server to the ui address so alert links open it. See
Dashboard on its own host.
Several servers
┌─────────────┐
SDKs → LB│ Server x N │→ PostgreSQL
└─────────────┘
│
shared volume for source mapsRunning more than one server needs PostgreSQL, since SQLite is a single file
on one machine. Every instance needs the same SESSION_SECRET_KEY, so a
session cookie from one is valid on the others, and the same
SOURCEMAP_STORAGE_PATH on a shared volume, so a source map uploaded to one
instance can be read by all of them.