Follow

Keep up to date with the latest Stelia advancements

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

What Rust is and how it earned its place in our system design

Rust is an important tool in our engineering toolkit. We break down why we use it, and equally when we’d reach for something else.

At Stelia, we treat programming languages as engineering tools, selecting them based on the constraints and requirements of the system rather than defaulting to a single choice.

Different problems call for different tools, and part of building reliable systems at scale is knowing which tool belongs where. Rust is one of these, and one that has earned a specific and important place in our system design. This piece explores what Rust is, why we use it, and equally, the situations that it doesn’t suit as well.

What is Rust?

Rust is a systems programming language, comparable in its use to C and C++, but meaningfully different in how it feels to work with. Where C and C++ are powerful but demanding, Rust focuses heavily on developer ergonomics: making the experience of writing, building, and maintaining code as straightforward as possible without sacrificing what makes systems language valuable in the first place.

The characteristics that make Rust favourable fall into three categories:

  1. Making it as simple as possible to write and run code – achieving this partly through Cargo, its build system, which is standardised across the entire ecosystem.
  2. High-level abstractions are genuinely cost-free – the patterns that make code expressive and readable in higher-level languages like Python or Java typically carry a runtime cost. In Rust, they don’t; the abstraction is free.
  3. Making it as difficult as possible to produce incorrect code.

That last characteristic is where Rust becomes very interesting. The Rust compiler works hard to prove correctness before your code ever runs. A great example of this is what the Rust community calls fearless concurrency – the compiler makes it impossible to create a scenario where a value is being overwritten while it’s being read elsewhere. In most languages, that kind of bug surfaces in production, but with Rust, it doesn’t compile.

How Rust earned its place in our stack

At an early stage, building in Rust was not the right choice for us. Instead, we began in Python. Python excels when the domain is still being defined. One of Rust’s core strengths is the ability to encode the entire domain model into the type system – facts about how the system works live in the code itself, and the compiler verifies them. But that strength comes with a requirement: the domain needs to be fully understood before you can represent it. If you’re still in discovery, figuring out the shape of the system, that’s a commitment you can’t yet make. Python delivers rapid results and data without requiring you to have all the answers up front.

This mirrors a pattern well established in high-performance computing – prototyping in Python before rewriting performance-critical components in C or C++ has long been standard practice. With Rust, the same logic applies.

As Stelia’s platform expanded to reach up to fifteen interacting services, the same openness Python offered actually began to hinder us. We needed to be able to modify components with full confidence that other services remained unaffected. Achieving this reliability in Python would have required a large, costly integration test suite, and the effort of building that out reliably would likely have exceeded the work of porting the code itself.

Much of our platform work also involves direct interaction with native OS components and libraries. In Python, that’s achievable, but it means building wrappers, which adds both development and runtime cost. In Rust, those interactions are native. And once the domain is understood and encoded, if something breaks, it breaks at build time – not during live deployment.

Python bindings and the storage layer: a practical example

That said, adopting Rust where it makes sense doesn’t mean committing to it for everything. Certain components have requirements that point clearly to Rust; others don’t, and a well-architected platform reflects that. Multiple languages can coexist, and Python bindings are a good illustration of how.

A specific component can be written in Rust and exposed to the broader stack – including Python services – through a binding layer. The Rust component handles what it needs to with precision and zero overhead; the surrounding system calls it as it would any other interface. Each language does the job it’s suited for, without either dictating the other.

Our storage layer is a concrete example of this in practice. It interacts directly with Ceph, providing both block (storage) devices and S3-compatible object storage, and needs to do so with zero overhead. The nature of that interaction – low-level, performance-sensitive, tightly coupled to the underlying infrastructure – makes it a natural fit for Rust. Building the equivalent in Python would require significant workarounds, whereas in Rust it is relatively straightforward. It is a component that makes sense in Rust regardless of what surrounds it, and bindings are what make that possible without disrupting the rest of the stack.

It’s a useful illustration of how language decisions work in practice. It’s not about choosing one language and applying it universally, but rather about understanding where the requirements of a specific component point, and building accordingly.

Rust and Python: understanding where each fits

A question we often get asked is how we actually make the call between these different language options in practice. The honest answer is that it comes down to a handful of factors. The table below captures how those factors tend to map across Python and Rust.

 PythonRust
Stage of developmentExploration, research, discovery – when the domain is still being defined.Production – when the architecture is established, and the direction of travel is clear.
Domain stabilityEvolving or uncertain – where the domain is still evolving and certainty can’t yet be encoded into the codeStable and well-understood – where encoding domain knowledge into the code adds value.
Compiler verificationLimited – incorrect assumptions surface at runtime or in production.Strong – the compiler proves correctness before the code runs.
Ecosystem and dependenciesLarge ecosystem, wide dependency trees, harder to audit fully.Smaller, more contained ecosystem, easier to reason about everything you depend on.
Developer experienceFast to write, low barrier to entry, excellent for prototyping.Standardised toolchain (Cargo), consistent across the ecosystem, easier onboarding onto established projects.
Codebase scaleManageable at a smaller scale – harder to maintain confidence across many interacting services.Well-suited to complex platforms – type system keeps multiple services honest as the codebase grows.

Neither column represents a better language – instead, they illustrate different moments in the lifecycle of a platform, and different requirements of the components within it.

Language selection in practice

Language selection is an engineering decision like any other; it should follow the problem, not precede it. The stage of development, the stability of the domain, the nature of the component, and the expertise of the team: these are the inputs. The language is the output.

For us, those inputs have often pointed to Rust at the production stage of our platform. For another team, with a different codebase, different requirements, or different engineering backgrounds, they might point somewhere else entirely.

What we’d push back on is the idea that language choice is a one-time decision made at the start of a project. Our own journey – from Python to an incrementally ported Rust platform, with bindings connecting the two throughout – reflects something closer to the reality: language decisions evolve as the product does, and the best engineering teams stay deliberate about them at every stage.

Enterprise AI 2025 Report