120,000 Lines of Rust: Inside the Nosdesk Backend
Published: 28 May 2026
I wrote before about why I built Nosdesk, and somewhere in that story I said I chose the hard path with Rust and it paid off. That post was about the product. This one is about what powers it.
What started as a handful of files has grown, over a year or so, into something close to 120,000 lines of Rust across roughly 260 modules, with around 1,030 tests holding it in place. It still ships as a single binary that comes up with one docker compose up . The stack stayed deliberately small: Actix-web on top, Diesel over Postgres for storage, Redis for fan-out, Tokio running everything underneath.
Three habits ended up shaping the work, and they run through everything below:
Push the dangerous mistakes into the type system, so the wrong thing won’t compile instead of merely being discouraged. Split the pure logic from the I/O around it, so the tricky parts become functions you can test without a database or a socket. Make comments explain why, not what: the alternative I rejected, the RFC I’m honouring, the bug that taught me the lesson.
Everything Is a Pipeline
When a client connects to Nosdesk, the first thing it does is pull a full snapshot of everything it’s allowed to see (bootstrap sync), which on a real workspace is a lot of rows. Load that into a Vec and serialise it in one shot and you get a workspace-sized memory spike on every connection.
So bootstrap is a stream. Rows are serialised as newline-delimited JSON and pushed through an mpsc::channel(64) , so a slow reader back-pressures the producer instead of pinning the whole result set in RAM. Diesel is synchronous, which means the query side runs on spawn_blocking and the bytes come back through a ReceiverStream . The whole snapshot lives inside one transaction, so the client sees a consistent point-in-time view even while other writes are landing.
That shape repeats throughout the codebase: a bounded buffer, the blocking work pushed off the runtime, back-pressure as a feature. Once you see data flow as a pipeline where the producer can outrun its consumer, you stop writing code that falls over under load.
... continue reading