ADR 002 — Rust + Axum for the Control Plane
Synced read-only from
/home/synnet/mirrors/synvirt-product/docs/decisions/002-rust-axum-for-control-plane.md. Edit at the source, not here.
ADR 002 — Rust + Axum for the Control Plane
Section titled “ADR 002 — Rust + Axum for the Control Plane”Status: Accepted Date: 2026-04-18 Deciders: SYNNET Engineering
Context
Section titled “Context”SynVirt’s control plane daemon (synvirt-daemon) needs to:
- Run continuously on each node as a long-lived system process
- Serve an HTTPS management API and web interface
- Eventually interface with KVM/libvirt, DRBD/LINSTOR, and etcd
- Be deployable as a single binary with minimal runtime dependencies
- Handle concurrent API requests without introducing memory unsafety bugs that could compromise the host system
- Maintain low memory footprint even on a fully loaded hypervisor node where every CPU cycle and MB of RAM is allocated to guest VMs
Decision
Section titled “Decision”Implement synvirt-daemon in Rust using the Axum web framework,
compiled to a single static (or minimally linked) binary. TLS is handled
natively by Rustls with no OpenSSL dependency.
Rationale
Section titled “Rationale”- Memory safety without GC pauses: The control plane daemon runs on the same host as guest VMs. A garbage collector pause in the daemon could delay critical operations (VM startup, health reporting, HA failover triggers). Rust’s ownership model eliminates both memory unsafety and GC pauses.
- Async with Tokio: Axum is built on Tokio, Rust’s production-grade async runtime. Concurrent API requests are handled efficiently without thread-per- request overhead, keeping daemon memory usage low.
- First-class Rustls support: Axum has native Rustls integration via
axum-serveroraxum-rustls. This eliminates the OpenSSL dependency that would otherwise require careful version management and patching. - Single binary deployment: A Rust binary with static linking requires no
runtime interpreter, no VM, and no external library installation on the
target node. The entire control plane is one file copied to
/opt/synvirt/bin/. - Type-driven correctness: Rust’s type system catches entire categories of bugs at compile time (null dereferences, race conditions, incorrect state transitions). For a product where bugs can corrupt VM data or cause unplanned downtime, this is a meaningful safety margin.
- Ecosystem alignment: The Rust ecosystem has mature crates for everything
we need:
tokio(async),axum(HTTP),rustls(TLS),serde(config),libvirt-rs(KVM, Hito 2), and bindings for etcd clients (Cluster mode).
Consequences
Section titled “Consequences”- Steeper learning curve: Rust has a higher initial learning curve than Go or Python, particularly around the borrow checker. New contributors will need onboarding time.
- Longer compile times in development: A clean Rust build of a non-trivial
codebase takes minutes. Incremental builds are fast, but initial builds on
developer machines are slow compared to Go or interpreted languages.
Mitigated by incremental compilation and
sccacheon the Debian 13 native dev host. - Smaller hiring pool: Rust engineers are less common than Go or Python engineers in Mexico and LATAM. However, the core team already has Rust experience, and the language’s popularity is growing rapidly.
- Compile targets: All compilation happens on a Debian 13 host
(
SYNVirtDEVin our dev setup). Cross-compilation to other architectures is possible but not required in Hito 0.
Alternatives Considered
Section titled “Alternatives Considered”Go + net/http (or Gin/Echo/Chi)
Section titled “Go + net/http (or Gin/Echo/Chi)”- Pros: Simple, fast compilation, large talent pool, single binary output.
- Cons: Go’s garbage collector, while significantly improved in recent versions, still introduces periodic pauses that are unacceptable for a latency-sensitive hypervisor control plane. Go’s memory usage per goroutine is also higher than Rust’s async tasks. The type system provides fewer safety guarantees than Rust.
- Decision: Rejected. Performance and safety profile inferior to Rust for this use case.
Python + FastAPI
Section titled “Python + FastAPI”- Pros: Very fast development iteration, huge ecosystem, easy to hire for.
- Cons: Interpreted language with a runtime that must be installed on every node. Memory usage is high. CPython’s GIL limits true parallelism. Startup time is slow for a daemon. Type hints are not enforced at runtime. Deploying a Python service to a minimal Debian install adds significant complexity.
- Decision: Rejected. Runtime dependency and performance profile are incompatible with a hypervisor control plane.
Node.js (Fastify / Hapi)
Section titled “Node.js (Fastify / Hapi)”- Pros: Large ecosystem, easy async programming model.
- Cons: V8 heap memory consumption is large. A Node.js process on an idle server still consumes ~50–100 MB of RAM that could go to guest VMs. Deploying Node.js on a minimal server OS requires a runtime. No memory safety guarantees.
- Decision: Rejected. Memory profile and runtime dependency are inappropriate for a system service on a hypervisor node.