Developer abandons Rust web app after years, migrates to Node.js
Summary
A programmer's journey from Pascal to C, then web dev in PHP/Python, and finally Rust for a web app. Despite loving Rust's control and safety, they switched to Node.js due to faster iteration, better web ecosystem, and type-safe templates, concluding Rust excels in CPU-heavy tasks but Node.js is more practical for dynamic web development.
I built a web app in Rust and had to abandon it
I spent years building a commercial web application in Rust, only to ultimately migrate the entire project to Node.js. This was a painful decision after a long journey that started in a high school programming club.
My first language was Pascal, but I fell in love with C for its precise memory control. After school, I pivoted to web development with PHP and other dynamic languages because that's where the jobs were.
Rust felt like a revelation when it arrived. It promised C's low-level control with modern tooling. I was all in.
The Rust web development experiment
I successfully built and shipped a revenue-generating web app in pure Rust by the end of 2023. The backend was Rust, and the frontend was a statically generated Astro site.
I hit a wall. Maintaining and extending the application became unsustainable. The migration to Node.js marked the end of my Rust web experiment.
My perspective is specific: I'm a solo founder. My app's bottlenecks are the database, disk, or network—not areas where Rust's performance advantages shine.
Where Rust for the web fell short for me
The struggles were primarily in dynamic, frontend-adjacent areas. Type-safe templating was a major pain point.
Libraries like Tera or Handlebars separate the view from the data model. Renaming a field requires remembering to update both the template and the code. Macro-based solutions like Maud exist but exacerbate another core issue: compilation time.
Internationalization (i18n) support in Rust's ecosystem is notably lacking compared to Node.js. Node ships with full ICU support and Intl.* APIs for formatting. Rust's support is minimal and incomplete.
The crushing weight of compilation time
Rust's safety guarantees come with a compilation cost. On my CI/CD hardware—a VM with an Intel Core i5-7500 and 32GB RAM—a Rust deployment took about 14 minutes from push to production.
Twelve of those minutes were spent in the Docker compilation stage. This didn't even include running tests or Clippy, which I gave up on due to caching complexities.
- Rust deployment: ~14 minutes (12 min compilation)
- Node.js deployment: ~5 minutes (including linting & tests)
After moving to Node.js, I deploy more code three times faster with a full test suite.
Ecosystem gaps and development friction
The web ecosystem in Rust is less mature. Need an obscure third-party API client? You'll likely be writing it yourself. I ended up implementing and maintaining:
- Third-party API integrations
- A queue mechanism on top of PostgreSQL
- Webhook signature validation code
This is fun engineering work, but it comes at the expense of building core product features. These tools are standard in other web-focused languages.
Even with excellent tools like the Serde serialization library or the SQLx crate, development felt heavy. I wrote boilerplate to avoid `.unwrap()` and defined numerous custom error enums. Writing dynamic SQL queries with SQLx was particularly difficult.
Why Node.js won for my use case
Node.js, for all its flaws, is good enough for my type of web application. The ecosystem provides mature, type-safe solutions for my biggest pain points.
I now use Zod for validation, Kysely for type-safe SQL queries, and type-safe HTML components. I have one unified stack and, ironically, more practical type-safety in my daily workflow than I did with Rust, especially for templates and translations.
As a solo founder wearing every hat, iteration speed is everything. I found myself ignoring bugs and postponing features in the Rust app because addressing them meant re-entering the long compile-test cycle.
The right tool for the job
I don't regret the Rust experiment. It earned me valuable connections and speaking opportunities. I still love the language.
But Rust excels at CPU-bound, non-visual tasks—like API services or video processing. My web app's challenges were in the dynamic, UI-heavy layer where fast iteration is key.
My Rust containers used a lean 60-80MB of RAM. My Node.js containers start at about 117MB. That's the trade-off. For my specific job—a solo founder building a feature-rich web app—Node.js with TypeScript is currently the right tool.
Related Articles
Arcjet JavaScript security SDK reaches stable v1.0 release
Arcjet's JavaScript SDK v1.0 is now stable, offering embedded AI security for attack detection and spam prevention directly in code.
Salt language uses Z3 theorem prover to verify systems code at compile time
Salt is a systems language with Z3-proven safety at compile time, no runtime overhead, and arena-based memory management. It offers high performance, verified contracts, and ergonomic syntax.
Stay in the loop
Get the best AI-curated news delivered to your inbox. No spam, unsubscribe anytime.
