Latest News

Lessons Learned from Switching from Python to Rust

When I first decided to migrate our backend stack from Python to Rust, it wasn’t just about curiosity – it was born from real pain points around performance, deployment costs, and reliability under load. Python’s web ecosystem – especially FastAPI – is a joy to work with for productivity and rapid iteration. But as our traffic grew and performance ceilings became apparent, I wanted to explore what Rust could offer.

In this article I’ll share what I learned along the way: the advantages, the gotchas, and where each ecosystem still shines.

Performance Comparison: Rust (Actix-Web) vs. Python (FastAPI)

Raw Throughput and Latency

One of the first things that hit me when benchmarking was just how different the performance profiles are between Rust and Python web frameworks.

Across various independent benchmarks, Rust’s Actix-Web consistently outperforms FastAPI in raw requests per second and memory efficiency. In one community benchmark, Actix-Web handled thousands more requests per second with lower latency and far lower memory consumption compared to FastAPI.

This aligns with the broader observation that Rust’s zero-cost abstractions, and lack of a garbage collector, make it exceptionally efficient when serving HTTP at scale.

Real-World Implications

In my experience, this translated into:

  • Much higher sustained throughput in stress tests.
  • Less variability under load.
  • Lower idle memory usage compared to Python processes.

That said, benchmarks tell only part of the story: real-world bottlenecks are often database bound or network bound. For many applications, FastAPI’s performance is more than adequate, and tuning database access or caching yields greater gains than the language choice alone.

ORM Differences: Diesel vs SQLAlchemy

Switching ORM paradigms was one of the most culturally different parts of the migration.

Migrations System

In Python, we used SQLAlchemy with Alembic migrations – an approach that diffs your models and generates migration scripts automatically.

In Rust, we moved to Diesel, which takes a very different stance:

  • Migrations are written manually as explicit SQL files.
  • There is no auto-diff tooling.
  • You’re given more control – and more responsibility.

This was initially frustrating, but the discipline of writing migrations by hand led to clearer auditability and fewer surprises in prod.

Type Safety and Compile-Time Guarantees

Here’s where Diesel really changed how I think about database code: type safety at compile time.

Diesel generates Rust types based on your schema, so mismatched column names or invalid query constructs simply don’t compile. Concepts like check_for_backend and requiring explicit table_name declarations mean that entire classes of common bugs disappear before you ever run a query.

In comparison, SQLAlchemy only catches many errors at runtime. While this adds flexibility, it also means more reliance on tests for correctness.

Building and Executing Queries

Diesel’s query builder uses Rust’s type system and takes more lines of code compared to the more dynamic expressive style of SQLAlchemy – but the trade-off is that the compiler proves a lot for you.

After an adjustment period, I came to appreciate how Rust’s explicitness helps when navigating complex query logic during refactors.

Automatic OpenAPI Generation Support

One area where Python still feels ahead out-of-the-box is API schema generation.

FastAPI automatically generates OpenAPI documentation and ships with browser UIs like ReDoc and Swagger UI at /docs and /redoc, making it super easy for clients and teammates to understand and explore your API.

Rust’s ecosystem is evolving here. Tools like utoipa can generate OpenAPI specs for Actix-Web, but they feel more manual and fragmented compared to FastAPI’s seamless experience. There are community crates to serve Swagger or Redoc UIs too, but they require extra setup and annotation.

I expect this gap to continue narrowing – there are active efforts in the Rust community to bring a smoother API doc experience that rivals FastAPI’s.

Deploy Size: Compilation vs Dependencies

Rust Compilation Time

Rust’s compilation is famously slower than interpreted languages. During development, rebuilds – especially with large crates – can feel sluggish compared to rerunning a Python script.

But this cost is development time, not production time. Once compiled, Rust binaries are:

  • Fully compiled ahead of time
  • Self-contained (no virtualenv, typically no dynamic dependencies)
  • Very small footprint in container images

That makes deployments simpler and more predictable.

Python Dependency Footprint

Python apps often bring a large dependency graph: FastAPI itself, uvicorn, pydantic (now much faster thanks to Rust internals), database drivers, etc.

This increases:

  • Container size
  • Build complexity
  • Surface for dependency conflicts

Rust’s Cargo produces one binary that encapsulates everything (usually), which drastically simplifies the deploy story.

Maintainability

This was the area with perhaps the most personal growth.

Rust pushes you toward clear ownership boundaries, explicit error handling, and careful design. Once you’ve internalized Rust’s compile errors, the compiler itself becomes a strong guardrail against regressions.

In contrast, Python’s dynamism can feel effortless during early development – but that same flexibility sometimes leads to harder-to-diagnose bugs in production unless backed by a robust test suite.

Our Rust codebases have felt more resilient during large refactors, largely thanks to the compiler’s strictness.

Documentation and Developer Experience

FastAPI’s Auto Docs

FastAPI’s integration with OpenAPI, along with ReDoc and Swagger UI, makes onboarding new developers extremely easy. It’s one of the biggest wins I’ve seen in team productivity.

Rust Documentation Generation

Rust’s built-in documentation tooling (cargo doc) is phenomenal for code-level docs. It encourages writing documentation next to your code, and Rustdoc generates clean, searchable HTML documentation.

While this doesn’t replace a nice /docs endpoint out of the box, it does greatly improve code-centric documentation quality and discoverability.

Conclusion

Switching from Python to Rust for backend development wasn’t about favoring one language over the other – it was about aligning with our project’s priorities.

  • Rust gave us performance, predictability, and reliability in production traffic.
  • Python gave us speed of development and world-class ergonomics.

Both ecosystems are powerful. What changes with Rust is that many issues that would only show up at runtime in Python are instead caught at compile time in Rust, reducing surprises and outages.

Choosing Rust means investing in the learning curve – but for teams where performance and correctness matter most, the trade-off has been worth it for us.

Author Note

This article was written by the creator of Hytale Multiplayer, a website focused on technical articles and deep-dives into the game Hytale, including server development, tooling, and comparisons with related ecosystems such as Minecraft. If you enjoy practical, engineering-focused content, feel free to explore more articles there.

Comments
To Top

Pin It on Pinterest

Share This