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'])
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(())
}
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(())
}
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(),
})
}
🤖 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:
- Open any Python file.
- Set your target language to Rust in the status bar.
- Hover over any import statement (like
import requestsorimport pandas). - 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)
Cool 👍🏼