Skip to content

Latest commit

 

History

History
24 lines (19 loc) · 1.74 KB

File metadata and controls

24 lines (19 loc) · 1.74 KB

ADR-003: SQLite via sqlx

Status: Accepted Date: 2026-04-13

Context: Cloud mode needs persistent storage for projects, workspaces, and sessions. The data model is simple (three entities with CRUD), and the runner is a single-binary deployment — external database dependencies are undesirable.

Decision: Use SQLite via the sqlx crate with async runtime, WAL mode, and compile-time query checking.

Alternatives considered:

  • PostgreSQL — full-featured but adds an external dependency, requires a running database server, and is overkill for the data volume (hundreds of rows, not millions). Complicates single-binary deployment.
  • Embedded key-value store (sled, rocksdb) — no SQL, no migrations, no relational integrity. Would require hand-rolling queries and schema evolution.
  • In-memory only — simple but loses state on restart. Reconciliation would need to reconstruct everything from Docker state, which is lossy.
  • File-based JSON — no concurrency guarantees, no atomic transactions, fragile under crashes.

Consequences:

  • Zero external dependencies — SQLite is embedded in the binary
  • WAL mode enables concurrent async readers without blocking writers
  • Foreign key enforcement catches referential integrity bugs at the DB level
  • Compile-time query checking (sqlx::query! macros) catches SQL errors at build time
  • Optimistic concurrency via updated_at WHERE clauses prevents lost updates
  • Migrations in runner/migrations/ provide schema evolution
  • Trade-off: SQLite doesn't scale to multi-node deployments. If Relay ever needs horizontal scaling, this decision must be revisited. For a single-runner deployment, SQLite is the right choice.
  • SQLX_OFFLINE=true allows building without a live database (CI)