I'm excited to share the technical journey of building LogoM8, a logo generation platform built entirely in Rust. When I started this project, I wanted to challenge myself writing a full app in Rust, from the frontend to the backend. Intially, I my plan was to find a native way to do this, but after some research, I found that Rust can be used for web development as well with the promise of near-native performance and strong type safety.
On top of that, I've been fascinated with how Tony Dinh has been shipping Typing Mind as a webapp. This model of shipping apps completely blew my mind, because of its incremental nature where you first ship a frontend (and don't bother with the backend) and then add a backend later, if you find traction. This seems like such a great way of de-risking the time you spend.
Admittingly, the tech stack I chose is a bit niche on the frontend side of things, but I really wanted to understand the limits of this approach. When you Google "Should I use Rust for frontend development?", while some are really positive about using Rust, there are also a fair amount of people claiming that Rust is not ready for frontend development. The backend side is far less controversial, as Rust is "known" to be a great choice for performant backend development.
Regardless, without further ado here's what I'm using:
The decision to use Rust wasn't just about trying something new - it brought significant advantages:
Browser-Side Performance: Logo generation involves complex operations like image tracing. Rust's performance characteristics, combined with WebAssembly, allow us to handle these computations client-side without compromising user experience. While there does exist javascript libraries for this, I haven't found one that is as performant as the Rust ones. Hence, had I gone with TypeScript, I would probably have to use a backend for this.
Type Safety Across the Stack: One of the most powerful features is sharing API types between frontend and backend. Unlike TypeScript, where type safety can be bypassed with 'any', Rust's strict typing catches issues at compile time.
React-Like Development: Once you get past the initial learning curve, Yew provides a familiar component-based architecture. Here's a quick example:
use yew::prelude::*;
use wonopui::{Button, Container};
#[function_component(LogoGenerator)]
pub fn logo_generator() -> Html {
let generating = use_state(|| false);
html! {
<Container>
<Button
onclick={move |_| generating.set(true)}
loading={*generating}
>
{"Generate Logo"}
</Button>
</Container>
}
}
That doesn't look too hard, does it? In fact, I quite enjoyed that there was no rollup, webpack or babel to configure (with all the horrors this occassionally involves).
The bad things:
Progressive web does not yet work with WebAssembly. However, I think this is only an issue if you are building a monster sized app and optimising the delivery of the app goes a long way. Certainly if the long term deliver will be a Tauri app, this is not an issue.
The ecosystem is still young. I had to build my own UI library, because there wasn't a good one available. This is a bit of a pain, but I think it's worth it in the long run. I could have chose to only write the components I needed, but got carried away and wrote a full UI library (still beta). I am planning to use this in other projects as well.
Coming from a React background, I was pleasantly surprised by how familiar the development experience felt. Yew's component model follows similar patterns, and WonopUI provided the building blocks needed for rapid UI development.
The real power became apparent when dealing with complex state management and API interactions. Rust's type system ensures that our API contracts are always upheld, catching breaking changes before they reach production.
I deploy on Kubernetes, which might seem like overkill for a Rust application (given its low resource usage), but it provides the flexibility we need for scaling. Most importantly though, it makes it super easy to roll out the next version. The entire backend service typically runs with minimal resource allocation, thanks to Rust's efficiency.
Initial Learning Curve: While Rust has a reputation for being difficult to learn, the investment pays off in reliability and performance.
Ecosystem Maturity: The Rust web ecosystem is younger than JavaScript's, but it's growing rapidly. I found everything I needed, although sometimes I had to build custom solutions. Overall, I was really positively surprised.
Build Times: Rust's compile times can be longer than JavaScript builds, but the trade-off is worth it for the runtime safety and performance.
Building LogoM8 in Rust has validated my belief that Rust is ready for full-stack web development. The combination of performance, safety, and developer experience has exceeded my expectations. Most importantly though, I had a blast building it! And I am not missing those nights debugging why Webpack wasn't behaving, let alone the need to monkey patch your code with react-rewire or the like!
I'm excited about the future of Rust in web development, and LogoM8 is just the beginning. I'm already planning my next projects using this stack. The ability to write high-performance, safe code that runs both on the server and in the browser opens up possibilities for more sophisticated web applications.
Feel free to ask any questions about my tech stack or share your experiences with Rust in web development! Or if you feel like trying the app (still beta), head over to http://app.logom8.com