Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Rewrite a Ruby on Rails service in Rust only when production measurements show a meaningful problem that a rewrite is likely to solve—and the expected benefit justifies rebuilding and maintaining the service’s behavior. Rust’s reputation and benchmark results from other applications are not enough. Start by locating the bottleneck, compare less disruptive fixes, then prove the case with a representative benchmark and a migration plan.

Start with the problem, not the language

Use production data to establish whether the Rails service has a costly constraint: latency, throughput, CPU, memory, reliability, or scaling cost. Break down the time and resource use. Application CPU work is different from time spent waiting on a database, network, queue, or external service; a rewrite may not address a bottleneck dominated by those waits.

If the service meets its objectives at an acceptable operating cost, there is no demonstrated rewrite benefit yet. Define the specific outcome you want—such as lower p99 latency, more throughput per core, or reduced memory use—and how you will measure it.

Compare realistic options before committing

A rewrite is one possible response, not the default response to a slow or expensive service. Compare the existing Rails implementation with targeted improvements, an incremental Rust extraction, and a full replacement.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Option What it changes What to establish
Keep the current Rails service No implementation change. Whether it continues to meet service objectives and cost targets.
Optimize Rails Adjust query behavior, caching, algorithms, background work, deployment configuration, or modernize the Ruby/Rails implementation in place. Whether a measured change addresses the identified constraint at lower total cost and risk.
Extract a Rust component Move a bounded function or endpoint behind a clear interface while leaving the rest in place. Whether the component can be tested and operated independently, and whether staged traffic proves the expected benefit.
Replace the service in Rust Reimplement and cut over the complete service boundary. Whether the performance or resource benefit justifies full parity, migration, rollback, and ongoing maintenance work.

Measure these options against the same workload and evaluate total implementation and maintenance cost, compatibility, security and failure behavior, deployment complexity, rollback, and team capacity. No option is guaranteed to solve a particular service’s problem until it is measured.

Choose a candidate that can be bounded

A promising Rust candidate has a clear interface, constrained behavior, and enough traffic or resource use for an improvement to matter. Its edge cases should be knowable and testable. A large, entangled Rails application with implicit behavior is a riskier first target than a small service or isolated endpoint.

Grab Engineering’s 2025 counter-service case study chose a high-QPS service with two main functions. Its authors caution that rewriting just to use Rust is not a sound business justification. The example is useful for thinking about scope, but it is a Go-to-Rust migration, not evidence of Rails-versus-Rust performance.

Build a benchmark that answers your question

Use equivalent hardware, input data, and traffic patterns for the current service and the proposed implementation. Include the route families and background jobs that matter in production. Record throughput; p50 and p99 latency; CPU and memory at idle and under load; cold-start behavior; database and queue effects; and operational cost. Basecamp’s Campfire conversion plan includes equivalent seeds and hardware, and calls out route, Action Cable, memory, cold-start, upload, and search measurements.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Make the benchmark representative rather than convenient: include realistic payloads, concurrency, hot and cold paths, and failure behavior. Report the measurement setup alongside every result. A benchmark of a narrow operation cannot establish how an entire service will behave.

What published figures do—and do not—show

Basecamp’s ONCE Campfire in Rust repository reports a 2026 benchmark on an AMD Ryzen AI MAX+ 395, with 16 concurrent clients and four hardware threads allocated to each app. It lists 241 Rails versus 36,260 Rust room-page requests per second; 413 versus 40,872 messages-page requests per second; 435 versus 33,299 search requests per second; and 273 versus 6,896 message-post requests per second. These are results for that Campfire port, code, and workload—not a general Rails/Rust ratio or a forecast for another service.

Grab Engineering reported an indicative 1,000 QPS using 20 cores for its original Go counter service and 4.5 cores for the Rust version. In shadowed traffic, p99 latency was similar or slightly worse. This Go-to-Rust result illustrates why resource use and latency must be evaluated separately; it does not predict a Rails migration’s outcome.

Budget for behavior, not just implementation

The Rust version must reproduce the service’s externally visible contracts. Before implementation, inventory what clients and neighboring systems depend on:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • HTTP status codes, headers, HTML and JSON responses, authentication, and cookie behavior.
  • Validation rules, errors, database effects, and time-dependent behavior.
  • Background jobs, uploads, real-time events, and failure or retry semantics.
  • Security properties, including behavior that may not be obvious from a successful response comparison.

Use fixed reference outputs or differential tests against the Rails implementation. Basecamp describes generating golden vectors from the reference application and comparing compatibility across HTML, DOM, accessibility trees, assets, Action Cable frames, and screenshots. As its conversion plan puts it, “We never port one from our reading of the docs.” Agreement with the reference app is valuable, but it does not by itself prove security.

Parity can involve deliberate trade-offs. In the Campfire port, the Rust implementation retains SQLite, the storage layout, and current cookie formats, while documenting differences. For example, it replaces Redis/Resque jobs with in-process queues, which can lose queued work if the Rust process crashes. Its documented limits also include CSRF expectations, media formats, request size, WebSocket limits, and selected legacy cookie paths. These are Campfire-specific choices and constraints, not characteristics of every Rails-to-Rust rewrite.

Include the parity suite, migration and rollback work, parallel operation, training, incident response, and long-term maintenance in the cost estimate. Compare that full cost with measured savings or product value over a stated period. The available case studies do not establish a universal rewrite budget, schedule, payback period, or expected cost reduction.

Check whether the team can own the Rust service

A rewrite creates an ongoing operational responsibility, not just a delivery milestone. Confirm that multiple people can review, deploy, troubleshoot, and maintain the new service—or define a credible plan to build that coverage. Grab’s case study identifies Rust learning and reliance on a single experienced developer as sustainability concerns. Include on-call readiness and incident response in the plan, not only initial implementation capacity.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Prefer a staged cutover when the boundary allows it

  1. Isolate a component or endpoint. Define its interface and the behavior it owns; keep unrelated Rails functionality out of the first migration.
  2. Build the reference tests. Capture representative inputs and Rails outputs, including errors and side effects, before changing production traffic.
  3. Run the Rust version alongside Rails. Where safe, shadow or replay representative traffic and compare outputs without allowing duplicate side effects.
  4. Shift traffic gradually. Increase the Rust share only as compatibility, performance, and operations meet explicit acceptance criteria.
  5. Keep rollback available. Plan how to return traffic to Rails and account for writes, queued jobs, and state created during the cutover.

A full replacement can still be reasonable when the service boundary is clean and parity work is explicit, but it makes migration and rollback planning especially important. JetBrains’ 2026 discussion of Rust rewrites likewise emphasizes staged migration and compatibility testing.

Make the decision with evidence from your service

Proceed when a measured constraint is substantial, the candidate is bounded, a representative test supports the expected benefit, the full lifecycle cost is acceptable, and the team can safely own the result. If those conditions are not met, optimize or continue operating Rails while gathering better measurements. The strongest direct Rails-to-Rust example here is Basecamp’s particular Campfire port; other cited rewrite evidence concerns Go or broader Rust compatibility work. None can substitute for testing your workload.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.