Brand logo
HomeCloud ComputingSecuritySoftware DevelopmentAI ApplicationsStartupsGeneral
  1. Home
  2. /
  3. softwaredevelopment
  4. /
  5. rust-dioxus-one-year-production-ci-build-times

ItInsightsWorld SoftwareDevelopment: Production Rust, Painful CI, and the Dioxus Trade-Off

For teams shipping a feedback product for SaaS, the most useful lesson from SeggWat after a year on Dioxus is not whether Rust wins over other stacks; it is that CI can quietly dominate delivery. The app's release path was stable enough that the runtime stayed boring in production, yet GitHub-hosted CI introduced repeated friction: each full release took about 90 minutes, and the WASM portion alone consumed about 22 minutes on 6 cores.

The original article asked whether Rust was the right foundation for a production micro SaaS back in April. This SoftwareDevelopment retelling keeps the engineering question: what happens after deployment when the stack is one language, the dashboard is small, and the pipeline has only two expensive compile targets? The answer is nuanced: shared types and a Cargo workspace remove fear during late at night refactors; compile-heavy CI, a 2-core runner, and a linter needing swap add cost to every release.

What the product stack looked like

SeggWat is an in-app feedback tool for SaaS products. The dashboard is a Dioxus 0.7 Fullstack application. Fullstack here means one Rust codebase doing three jobs: server rendering, server functions as backend, and client compilation to WebAssembly. The product sits in a Cargo workspace with a backend crate, an auth crate, and about ten UI crates covering insights, feedback, ideas, boards, widgets and settings. Twelve crates depend on Dioxus. The data layer uses PostgreSQL.

infra.page runs the same stack.

Engineering outcomes that helped

Context switching dropped

For a solo founder or a small product team, one toolchain, one formatter, and one set of habits reduce overhead. There is no separate frontend brain and backend brain to warm up. When the team opens the workspace, the work continues.

The benefit is not typing speed; it is change confidence. A struct can be defined once, returned by the data layer, sent by a server function, and rendered by a component. When a field is renamed, cargo check reveals the broken sites, including UI code. There is no OpenAPI document to regenerate and no TypeScript interface drifting behind the backend. That mattered late at night, when no reviewer was available.

Production behavior became predictable

The dashboard was designed to be dull once it compiled. A class of JavaScript runtime surprises, such as undefined is not a function, did not reach users, so remaining issues were closer to product logic. The boring in production argument from April survived real traffic.

Future targets were considered

Dioxus can target desktop and mobile, including iOS, from one component model. The products did not need a native app at the time. Still, that option reduced the risk of a full rewrite if a later requirement demanded an app.

The CI and compile pain

The painful part was the build path. The dashboard compiles twice: once for the server and once for wasm32. A dozen Dioxus crates, macro-heavy UI code, and a dependency tree large enough for a multi-crate workspace made compiling dominant. Local builds were manageable on a capable machine. Pipeline builds were not.

Measured pipeline costs

  • The WASM build alone took about 22 minutes on 6 cores, even though it was one leaf crate: the browser dashboard.
  • A release image took about 90 minutes on a GitHub-hosted 2-core runner. The same release took around 40 minutes on a VPS runner.
  • Clippy hit the memory ceiling. cargo clippy --workspace --all-targets on the 7 GB hosted runner failed with exit code 143 and no diagnostics. The practical mitigation was a 10 GB swapfile plus CARGO_BUILD_JOBS=1 to lower peak memory.
  • The team stopped building images on every push to main. Images were built on release tags or manual triggers because 90 billed minutes per push was hard to justify.

Step tutorial: keeping release builds warm without rebuilding on every push

Based on the described workaround, teams using GitHub actions and Rust caches can adopt the following process. It does not add new results; it restates the pattern in action form.

  1. Use Swatinem/rust-cache for the Cargo build cache.
  2. Accept that a workflow run can restore caches only from its own ref or the default branch.
  3. Remember that GitHub evicts caches unused for 7 days.
  4. If main builds are stopped to save 90 billed minutes, release builds may start cold.
  5. After a dependency bump, manually trigger a build on main to keep the cache warm.
  6. Build and test in one workflow step so tests reuse compiled artifacts instead of compiling everything twice.
  7. Move heavy builds to a self-hosted runner when release time matters; in the reported case, this reduced time from 90 minutes to around 40.
  8. Treat linker tuning, such as mold, as secondary when linking is not the bottleneck.

Comparison table: where the stack helps and where it costs

AreaPositive effectEngineering costPractical response
TypesShared structs across database, server function, and component remove API drift.Refactors still need compile cycles.Use cargo check as the source of truth.
Toolchainone language and one formatter lower context switching.frontend brain and backend brain disappear, but CI still splits targets.Keep local expectations honest: the dashboard compiles twice.
WebAssemblyBrowser interactivity comes from the same Rust code.about 22 minutes for the WASM build on 6 cores.Cache aggressively, and do not assume mold solves compile time.
Runtime reliabilityundefined is not a function class bugs are less likely.Logic bugs still require tests.Focus review time on behavior, not glue-code surprises.
FrontierDioxus keeps iOS and desktop paths possible.Topcoat removes the 22-minute WASM tax in the next bet, but gives up some multi-platform comfort.Choose by product shape, not framework evangelism.

The "All Rust" promise with its asterisk

The business logic was described as All Rust, but the edges were not pure. SeggWat's insights page uses charts. The author could not find a trusted Rust charting library, so the implementation used Chart.js from a CDN, wrapped in about 340 lines of JavaScript that Dioxus called through dioxus-use-js. Styling used Tailwind, so CI also installed Bun and ran the Tailwind CLI before Rust started. This is pragmatic, but it means the All Rust story includes a JS toolchain at the boundary.

Decision heuristics

People may ask, "What helps me ship fastest?" The more useful operating question is, "What helps me keep shipping without hating my life?"

Backend and frontend re-evaluation

For the backend, the reported verdict remained Rust. For the frontend, the verdict changed with product shape. If the product were truly app-like, with heavy client state, offline support, or a real mobile app, Dioxus would be a strong pick. Most work, however, was dashboard UI: forms, tables, a few charts, and toggles. For that shape, the team was paying a 22-minute WASM tax on every release for interactivity that was barely used.

Next engineering bet: Topcoat

The next project was planned to use Topcoat, a fullstack framework from the tokio-rs org announced in July. Its design choice is opposite to Dioxus on one point: everything renders on the server, components can be async functions, and queries can be called directly. For interactivity, $(...) expressions run as type-checked Rust; Topcoat evaluates them on the server for first render and translates them to JavaScript for the browser. There is no WASM bundle and no second compile target.

On paper, Topcoat preserves one language, shared types, and no separate API layer, while removing the part that hurt most: the 22-minute WASM build. The post was clear that this was a bet, not a measured result. Topcoat was described as early-stage and experimental, with breaking changes expected. The author gave up the multi-platform option and had not measured a single build yet. The planned follow-up promised real numbers: compile times, CI minutes, and anything missing from Dioxus. If release time dropped from 40 minutes to 10, the report would say so; if not, it would also say so.

FAQ

Did Rust make the app faster?

The source did not claim runtime speed as the main gain. It emphasized change confidence: cargo check showed broken sites when a field changed, and the stack avoided a separate OpenAPI or TypeScript drift path.

Why were releases slow if production stayed boring in production?

Because the pipeline still needed two compile targets. The WASM path consumed about 22 minutes on 6 cores, and the whole release image could need about 90 minutes on a GitHub-hosted 2-core runner.

Is the next stack proven?

No. Topcoat was early-stage and experimental. The article treated the switch as a bet, not a result, and said it had not measured a single build yet.

Common misconceptions

  • One language does not automatically mean one toolchain end to end. Chart.js, dioxus-use-js, JavaScript glue, Tailwind, Bun, and the Tailwind CLI showed that JS can remain at the edge even in a mostly Rust app.
  • A boring runtime is not the same as a boring pipeline. The product could be boring in production while CI stayed volatile because of the two compile targets.
  • Caching is not magic. Swatinem/rust-cache helped, but ref isolation and the 7 days eviction rule could leave release builds cold, especially after 90 billed minutes per push forced the team off every-push image builds.

Action recommendations for teams considering this path

  • If your product is mostly dashboard, estimate the WASM tax before choosing a Rust fullstack path.
  • Measure the two targets separately: server build and wasm32 browser build.
  • Put Clippy behind a memory plan, such as a 10 GB swapfile plus CARGO_BUILD_JOBS=1, before treating exit code 143 as a random CI fault.
  • Decide whether GitHub-hosted runners are acceptable when 2-core capacity can make a release last about 90 minutes; compare that with a self-hosted path around 40 minutes.
  • Keep a cache-warm schedule if release tags no longer build on every push to main.
  • Do not let the term Fullstack hide the boundary costs: PostgreSQL, WebAssembly, iOS optionality, and JS edges all shape delivery.
Brand logo

IT Insights

Cloud & Infrastructure Practice Media for Enterprise Technology Decision-Makers

Cloud ComputingSecuritySoftware DevelopmentAI ApplicationsStartupsGeneralAI Data News Global

© 2026 IT Insights.

Cookie Notice

We use cookies to improve your experience and analyze website traffic. Read our Privacy Policy to learn more.