Written by James Britt
A Ruby application can work well for years before one job starts taking too long. A nightly import may spend hours parsing files. A calculation may hold up requests even though the rest of the Rails application has little to do.
That is a useful point to investigate Rust. Ruby can handle application behaviour, database access and the web interface, while a smaller Rust component takes on the expensive processing.
Begin with the application itself. Find the bottleneck, establish how often it occurs, and separate time spent computing from time spent waiting. Those answers tell you where Rust might help your Ruby application.
When Rust Makes Sense in a Ruby Application
Profile the current code first. A slow endpoint may be waiting for a database query or an external API call. A missing cache may be the problem. Moving the surrounding Ruby code into Rust leaves those waits in place.
CPU-intensive work is a more useful candidate for a prototype. Examples include repeated calculations, processing large batches of records and parsing a specialised file format. The operation should have clear inputs and outputs so the Ruby and Rust implementations can be compared.
Suppose a Rails application imports supplier data overnight. If most of the job’s runtime comes from Ruby transformations, a Rust implementation of that step is worth measuring. If most of the runtime comes from database writes, investigate batching and query behaviour first.
Include the cost of moving data between languages in your measurements. Copying strings, converting collections and serialising messages can eat into the gain from faster computation. Test the complete job with representative data.
Three Ways to Connect Ruby and Rust
A Native Ruby Extension
A native extension lets Ruby call compiled Rust code within the same process. Magnus provides Ruby bindings for Rust, including ways to expose Rust functions as Ruby methods. The rb-sys project supplies lower-level bindings and tooling for building Rust-based Ruby extensions.
A native extension can suit a small operation called frequently through a stable interface. Packaging takes work, though. Your gem must compile or supply compatible binaries for the Ruby versions, operating systems and processor architectures your users need.
Memory handling deserves a careful review. Magnus documents restrictions on keeping Ruby objects in Rust heap structures because Ruby’s garbage collector may not find them. Rust’s ownership rules do not enforce every requirement at this boundary. A developer needs to understand both the Rust code and Ruby’s object lifecycle.
A Separate Rust Service
A Ruby application can send work to a Rust service through an API or a message queue. This gives the Rust component its own deployment and scaling arrangements.
Someone must manage the service’s timeouts, authentication, failed requests and message formats. Network calls and serialisation also add overhead. Measure that cost against the processing time saved before committing to a separate service.
For example, Rails might manage users and billing while a Rust service processes a substantial data stream. Define which system owns the data and how the Ruby application behaves when the service is unavailable.
A Rust Command-Line Tool or Worker
Batch work can also run in a Rust executable launched by a Ruby job. File conversion and scheduled data processing are possible uses.
Keep the interface explicit. Specify input formats, exit codes, error output and time limits. Avoid constructing shell commands from untrusted input, and decide what happens if a job stops halfway through.
For work that already runs outside a web request, an executable can be a manageable first experiment. You still need reproducible builds and a way to update it alongside the Ruby application.
What to Ask About Ruby Threads and Native Code
Adding Rust does not automatically make a Ruby application run work in parallel. In CRuby, the Global VM Lock affects how Ruby threads execute. Ruby’s extension documentation describes mechanisms for releasing the lock around suitable native work.
Ask a prospective partner which operations hold the lock, which release it, and how Ruby objects are protected during that work. Review the Ruby Thread documentation alongside the proposed design.
Measure concurrent requests as well as the isolated function. A calculation can finish quickly in a benchmark and still block other requests while it runs.
Development Partners a Ruby Team Could Assess
The companies below advertise different services. Use those descriptions to prepare a shortlist, then ask for evidence relevant to your Ruby application. The proposed Ruby use cases here are evaluation examples; confirm the experience of the engineers who would do the work.
Yalantis
Yalantis describes its Rust development team as working on embedded software, distributed backends, integration and modernisation. It also lists Rust team augmentation and long-term support.
A Ruby team could discuss a project in which Rails manages a device dashboard while a Rust component handles incoming device data. Ask the company to explain the interface, the failure cases and who maintains each part after delivery.
For healthcare or other regulated work, request the specific security and compliance deliverables. A language choice alone does not establish regulatory compliance.
Serokell
Serokell’s Rust services include backend development, systems programming, dedicated teams and application audits.
An audit could be a useful starting point for a Ruby project whose team has identified costly processing but has not settled on an architecture. Ask for a proposal that compares a native extension with a separate service, including deployment and maintenance costs.
For correctness-sensitive work, request examples of the tests or verification methods the proposed engineers would use. Define the properties that must hold, such as identical calculation results or predictable handling of malformed input.
BairesDev
BairesDev offers Rust development through staff augmentation, dedicated teams and outsourced projects.
Those models give a Ruby team several ways to divide responsibility. An internal Rails team might keep control of the application while additional engineers develop a bounded Rust component.
Meet the people proposed for the project. Ask how they would trace an issue across Ruby, the integration layer and Rust. Agree on code review, release ownership and support arrangements before work starts.
Digis
Digis advertises Rust staff augmentation and custom development, including backend, embedded and systems work.
This is worth discussing when an existing Ruby team needs additional engineering capacity for a specific component. Give candidates a small integration task that uses the application’s real input types and error-handling conventions.
Review how failures reach the Ruby application, then ask the engineers to demonstrate the build process. The component needs to run in your deployment environment as well as on their laptops.
RapidOps
RapidOps describes product development services covering discovery, product strategy, web development, APIs and platform integration.
That broader scope may be relevant when the Ruby application needs changes to its workflows or user interface as well as performance work. Ask how the team would decide which parts of the project benefit from Rust.
Its general product services should prompt a separate technical discussion. Request evidence of Rust delivery and Ruby integration from the engineers assigned to your project before including those capabilities in the contract.
LeewayHertz
LeewayHertz lists Rust development alongside Web3 and blockchain services on its website.
A Ruby team working on a blockchain-related product could ask about a Rust component that communicates with the relevant network while Ruby handles application workflows. Confirm experience with the particular chain, SDK and integration you need.
For background on the terminology, see blockchain (read more) and decentralized apps (more info).
Comparing Partners for a Ruby Project
| Company | Advertised area to discuss | Evidence to request for your Ruby application |
|---|---|---|
| Yalantis | Rust backends, embedded systems and integration | A relevant integration design and support plan |
| Serokell | Rust development and application audits | Profiling findings and a justified architecture |
| BairesDev | Staff augmentation, dedicated teams and outsourcing | Experience of the assigned engineers and release ownership |
| Digis | Rust staff augmentation and custom development | A working integration task and reproducible build |
| RapidOps | Product development and platform integration | Specific Rust experience and a clear reason to use it |
| LeewayHertz | Rust and Web3 services | Experience with the required network and Ruby interface |
Start With a Small, Measurable Trial
Give the shortlisted partner one operation to investigate, with representative inputs, expected outputs and measurements from the current Ruby implementation.
Agree on acceptance criteria before the prototype begins:
- Correctness: the result matches the agreed behaviour, including invalid input.
- Performance: the complete operation improves under realistic load.
- Deployment: the component builds and runs on the required platforms.
- Failure handling: errors reach the Ruby application in a usable form.
- Maintenance: your team receives the source, build instructions and an upgrade plan.
Include a rollback path. For a native extension, consider whether the original Ruby implementation can remain available during the trial. For a service, decide how traffic can return to the existing path.
At the end of the trial, your Ruby team should be able to explain what improved, what the component costs to operate and how to maintain it. Use those findings to decide whether to expand the work and continue with the partner.
