Rust on ESP32 and Single-Board Computers: Our Embedded Stack

In The Lean Stack I described how we went back to fundamentals on the web: HTML, CSS, JavaScript, Bun and Hono. This is the companion piece about the other end of our work — the devices. Sensor nodes, controllers, kiosks, edge boxes. Everything we now build there is Rust.
Why the embedded world needed the same reset
Embedded development had its own version of frontend hell. Vendor IDEs from the 2000s. C codebases where one stray pointer silently corrupts a sensor reading for weeks. Or the opposite extreme: MicroPython and Node on a Raspberry Pi, where your "firmware" is an interpreter, a package manager, and a prayer that nothing updates itself overnight.
Rust deletes both failure modes at once:
- No runtime, no garbage collector. The binary you flash is the program. Timing is predictable, memory usage is known at compile time, and there is no interpreter to break underneath you.
- Memory safety at compile time. The class of bug that has eaten decades of embedded engineering — buffer overruns, use-after-free, data races between an interrupt and the main loop — simply does not compile.
- One language from microcontroller to server. The same types that define a sensor reading on the chip can be shared with the ingestion service. No more reimplementing the same packet format in C, Python, and TypeScript and hoping the three agree.
Rust on the ESP32
The ESP32 family is our default microcontroller: cheap, everywhere, with Wi-Fi and Bluetooth on the chip. The Rust story on it has matured from experiment to production over the last few years, on two tracks:
- esp-hal (bare metal, no_std) — pure Rust against the hardware. Minimal footprint, full control, ideal for battery-powered sensor nodes that read, transmit, and sleep.
- esp-idf with std — Rust on top of Espressif's official framework. You keep the mature Wi-Fi, MQTT and TLS stacks, but write your application logic in safe Rust with real
Strings, threads, and the full crate ecosystem.
We use the second track for most commercial work: the battle-tested networking comes from the vendor, and the logic that actually encodes our business rules — calibration, batching, failure handling — lives in Rust where the compiler guards it.
The toolchain is refreshingly boring now: cargo build, flash over USB, done. The same cargo workflow as on the server. No vendor IDE in sight.
Rust on single-board computers
One level up from microcontrollers sit the single-board computers — Raspberry Pi and its industrial cousins — running gateways, local dashboards, and on-site data collection.
The lazy default here is Python scripts under systemd. It works until it doesn't: dependency drift, a distro upgrade that changes the interpreter, memory creep in a process that was supposed to run for a year.
Rust cross-compiles to a single static binary. You copy one file to the board and it runs — the same discipline Bun gives us on the web tier. An SBC deployed to a customer site is exactly the kind of machine you do not want to debug over a bad VPN connection at 11pm; a static binary with no runtime dependencies is how you avoid ever having to.
These boards are also where our local AI strategy touches the physical world: small models doing anomaly detection or vision inference on-site, with the Rust service feeding them and shipping only conclusions — not raw data — upstream to self-hosted infrastructure. Governance, all the way down.
The AI-agent angle
Here is the part that surprised me most: AI coding agents are exceptionally good at Rust.
It sounds backwards — Rust is supposed to be the hard language. But agents thrive on fast, honest feedback, and the Rust compiler is the most honest reviewer in the industry. The agent writes code, the borrow checker rejects it with a precise explanation, the agent fixes it — and when it finally compiles, an entire category of bugs is already provably absent. Compare that with C, where the code compiles instantly and then fails in the field three weeks later.
For a one-person team shipping firmware, that changes the economics completely. The compiler does the code review; the agent does the typing; you do the thinking.
The honest trade-offs
It is not free. Compile times are real. The ecosystem for exotic peripherals is thinner than C's, and sometimes you still write an unsafe block around a vendor driver. And the learning curve exists — the borrow checker humbles everyone for the first month.
But we pay those costs once, at development time, on our desks. The C alternative charges you later, in the field, on hardware you may not be able to reach. I know which invoice I prefer.
Closing thought
The lean stack principle is the same at every altitude: the fewest layers you can govern completely. On the web that meant HTML and Bun. On the devices it means Rust — one binary, no runtime, compiled proof that whole classes of failure cannot happen.
From a 240MHz microcontroller to a self-hosted server rack, it is fundamentals all the way down. 🦀