DEV Community

Cover image for Migrating from Python to Rust? Here's how to map your packages
Sagar Kashyap
Sagar Kashyap

Posted on

Migrating from Python to Rust? Here's how to map your packages

Porting Python code to Rust is one of the most common performance optimization plays in modern software engineering.

Whether you are rebuilding a bottlenecked web service (moving from FastAPI to Actix), accelerating a data pipeline (moving from Pandas to Polars), or rewriting a CLI utility, the performance gains are massive. Rust services routinely run 10x to 100x faster while consuming a fraction of the RAM.

But once you install Rust and set up your Cargo.toml, you hit the first roadblock: dependency mapping.

Python's PyPI ecosystem and Rust's Crates.io ecosystem look completely different. Python code relies on dynamic runtime patterns and heavy frameworks, whereas Rust prioritizes compiled type-safety, explicit memory management, and modular crates.

To save you hours of browsing crates.io, here is the ultimate cheat sheet for mapping common Python packages to their Rust equivalents, followed by a way to automate this directly inside your editor.


📊 Python ➡️ Rust Crate Mapping Cheat Sheet

Python Package Rust Crate Equivalent Why & How to Use It
requests reqwest The undisputed standard for making HTTP requests in Rust. Supports both async and blocking calls.
pandas polars Written natively in Rust, Polars is a lightning-fast DataFrame library. It’s so fast that Python developers actually import the Polars Python wrapper to speed up their Python code!
numpy ndarray Provides n-dimensional arrays, matrix operations, and numerical computation helpers.
FastAPI / Flask axum or actix-web Use Axum if you want a clean router backed by the Tokio team. Use Actix-web if you want one of the most mature and fastest web frameworks in the entire tech sector.
pydantic serde In Rust, you don't need a heavy library for validation and serialization. You declare standard Rust structs and derive Serde (serde_json) for ultra-fast JSON serialization/deserialization.
pytest cargo test (built-in) Rust has testing built directly into the language and compiler. For property-based testing (like Pytest's hypothesis), use the proptest crate.
sqlite3 rusqlite High-quality, ergonomic bindings to the SQLite database.
celery apalis or background-jobs For running background task workers. Or, for simple concurrency, you can often just spawn background asynchronous tasks using tokio::spawn.

🔍 In-Depth Mappings & Code Examples

1. HTTP Requests: requests ➡️ reqwest

In Python, fetching data from an API is famously simple:

import requests

response = requests.get('https://api.github.com/users/octocat')
data = response.json()
print(data['name'])
Enter fullscreen mode Exit fullscreen mode

In Rust, Reqwest handles this asynchronously (using Tokio as the runtime). We pair it with Serde to safely parse the JSON into a strongly-typed struct:

use serde::Deserialize;

#[derive(Deserialize, Debug)]
struct GithubUser {
    name: String,
}

#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
    let user: GithubUser = reqwest::Client::new()
        .get("https://api.github.com/users/octocat")
        .header("User-Agent", "rust-app")
        .send()
        .await?
        .json()
        .await?;

    println!("User Name: {}", user.name);
    Ok(())
}
Enter fullscreen mode Exit fullscreen mode

2. DataFrames: pandas ➡️ polars

If you are processing millions of rows of data, Rust's Polars will feel like moving from a bicycle to a rocket ship:

use polars::prelude::*;

fn main() -> Result<()> {
    // Read a CSV and filter rows where age > 30
    let df = CsvReader::from_path("users.csv")?
        .has_header(true)
        .finish()?
        .lazy()
        .filter(col("age").gt(lit(30)))
        .collect()?;

    println!("{}", df);
    Ok(())
}
Enter fullscreen mode Exit fullscreen mode

3. Web Frameworks: FastAPI ➡️ Axum

FastAPI is loved for its automatic type validation and clean path routing. In Rust, Axum uses a declarative handler system that feels very familiar to FastAPI developers, but runs with near-zero latency overhead:

use axum::{routing::get, Json, Router};
use serde::Serialize;

#[derive(Serialize)]
struct Status {
    status: String,
}

#[tokio::main]
async fn main() {
    let app = Router::new().route("/status", get(handler));

    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
    axum::serve(listener, app).await.unwrap();
}

async fn handler() -> Json<Status> {
    Json(Status {
        status: "ok".to_string(),
    })
}
Enter fullscreen mode Exit fullscreen mode

🤖 How to automate this in VS Code

Instead of context-switching to browser tabs to find crate names and boilerplate code, you can use PackagePal.

It is a free VS Code extension that does the lookup for you directly inside your editor:

  1. Open any Python file.
  2. Set your target language to Rust in the status bar.
  3. Hover over any import statement (like import requests or import pandas).
  4. Instantly see the best crate equivalents, usage code snippets, and direct links to official documentation.

It supports 13 languages (including Rust, Go, Python, Node.js, and Java) and is completely private—it uses your own free Gemini API key stored securely in VS Code’s native secret storage.


Over to you!

If you've migrated Python services to Rust, what was the most difficult package mapping you had to write? Let me know in the comments below! 👇

If you found this cheat sheet helpful, check out *PackagePal on the VS Code Marketplace** and give the project a star on GitHub!*

Top comments (1)

Collapse
 
nube_colectiva_nc profile image
Nube Colectiva

Cool 👍🏼