wandres.dev
PUBLICAR Y ECOSISTEMA · crates.io, docs.rs

El ecosistema esencial: las crates que todo Rustacean conoce

La biblioteca estándar de Rust es deliberadamente pequeña: no trae serialización, ni runtime async, ni cliente HTTP. Esa ausencia es una decisión de diseño que delega en el ecosistema, donde un puñado de crates fundacionales —serde, tokio, clap, rayon, reqwest, axum— se han vuelto estándares de facto y lenguas francas sobre las que se apoya casi todo lo demás.

⏱ 18 min

Si vienes de lenguajes con «pilas incluidas», la biblioteca estándar de Rust te parecerá austera hasta el desconcierto: no trae serialización JSON, ni un runtime asíncrono, ni un cliente HTTP, ni parseo de argumentos de línea de comandos. No es un olvido: es una postura. La std de Rust promete estabilidad perpetua —lo que entra jamás puede romper—, así que se restringe a lo verdaderamente universal y delega el resto en crates.io, donde las librerías pueden evolucionar, subir mayores y competir. El resultado es que ser productivo en Rust exige conocer un canon: media docena de crates fundacionales que la comunidad ha coronado como estándares de facto. No dominarlas es reinventar mal lo que decenas de miles de proyectos ya comparten. Esta lección es el mapa de ese canon.

🎯 Al terminar esta lección sabrás
  • Entender por qué la std es pequeña a propósito y qué llena el ecosistema en su lugar.
  • Reconocer las crates fundacionales —serde, tokio, clap, rayon— y el problema que resuelve cada una.
  • Situar el grafo de la web asíncrona: hyper, tower, axum, reqwest sobre tokio.
  • Identificar las lenguas francas cuyos traits comparten miles de crates entre sí.

Por qué la stdlib es pequeña a propósito

La decisión de fondo es un intercambio entre dos garantías incompatibles. La std ofrece estabilidad absoluta: código escrito hace años sigue compilando, porque la biblioteca estándar nunca publica una versión mayor que rompa. Pero esa misma inmovilidad sería veneno para una API de serialización o un runtime async, dominios donde el conocimiento del arte avanza rápido y a veces hace falta rehacer las abstracciones. Meter serde o tokio en la std los congelaría en su primer diseño para siempre.

Al dejarlos fuera, Rust les concede lo que necesitan: serde y tokio pueden iterar, aprender de sus errores y publicar mayores cuando corresponde, sin arrastrar a la std ni romper la promesa del lenguaje. El precio es que el recién llegado debe saber qué instalar. La std conserva lo eterno —tipos, colecciones, Result, hilos, Iterator— y el ecosistema aporta lo que evoluciona. Conocer el canon es, por tanto, parte de saber Rust.

Las crates fundacionales

Estas son las columnas del ecosistema, las que aparecen en el Cargo.toml de una fracción enorme de todos los proyectos:

🔄

serde

El marco de serialización. #[derive(Serialize, Deserialize)] sobre tus tipos, y serde_json, toml o bincode como formatos. Su rasgo genial: separa el modelo de datos del formato concreto.

⚙️

tokio

El runtime asíncrono dominante. Ejecuta tus Future, programa tareas sobre un pool de hilos y ofrece E/S sin bloqueo, temporizadores y canales. El corazón de casi todo lo async.

🖥️

clap

El parseo de argumentos de línea de comandos. Con #[derive(Parser)] describes tu CLI como un struct y obtienes ayuda, validación y autocompletado gratis.

🧵

rayon

Paralelismo de datos casi mágico: cambia .iter() por .par_iter() y tu bucle se reparte entre todos los núcleos, con la seguridad de datos garantizada por el compilador.

🌐

reqwest

El cliente HTTP de alto nivel. Peticiones async (o bloqueantes), JSON con serde integrado, TLS, cookies y redirecciones. Construido sobre hyper y tokio.

🚏

axum

El framework web ergonómico del ecosistema tokio. Enrutado por tipos, extractores, y compatible con el middleware de tower. Servidores async idiomáticos.

Un vistazo a serde basta para captar por qué estas crates dominan: la ergonomía es la de la biblioteca estándar, pero el poder es de una librería que pudo evolucionar. Deriva dos traits y tu tipo habla ya con cualquier formato del ecosistema:

use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
struct Config { host: String, puerto: u16 }

let c = Config { host: "localhost".into(), puerto: 8080 };
let json = serde_json::to_string(&c)?;            // a JSON
let vuelta: Config = serde_json::from_str(&json)?; // y de vuelta
let toml = toml::to_string(&c)?;                   // el MISMO tipo, otro formato

El struct no sabe nada de JSON ni de TOML: serde separa el modelo de datos del formato, y esa abstracción es la que convierte un tipo cualquiera en universalmente serializable.

Más allá de esta primera fila hay una segunda que también conviene tener en el radar: anyhow y thiserror para errores (que ya recorriste), tracing para observabilidad estructurada, regex para expresiones regulares, rand para aleatoriedad, itertools para adaptadores extra de iterador, sqlx y diesel para bases de datos, criterion para benchmarks, y proptest para pruebas basadas en propiedades. Ninguna vive en la std, y todas son, en la práctica, tan estándar como si lo estuvieran.

El grafo de la web asíncrona

Las crates no son islas: se apilan. El ejemplo canónico es la pila web de tokio, donde cada capa se construye sobre la anterior y tower aporta un vocabulario común de middlewareService— que tanto el servidor como el cliente reutilizan:

flowchart TD
MIO[mio E/S del sistema epoll o kqueue] --> TOKIO[tokio runtime tareas y temporizadores]
TOKIO --> HYPER[hyper implementacion de HTTP]
HYPER --> TOWER[tower abstraccion Service y middleware]
TOWER --> AXUM[axum servidor web]
TOWER --> REQWEST[reqwest cliente HTTP]
style TOKIO fill:#89b4fa,color:#11111b
style TOWER fill:#f9e2af,color:#11111b
style AXUM fill:#a6e3a1,color:#11111b
style REQWEST fill:#cba6f7,color:#11111b

Entender este apilamiento es entender por qué elegir tokio como runtime arrastra decisiones: axum, reqwest, sqlx y buena parte del mundo async asumen tokio por debajo. La coordinación no es casual; es lo que permite que middleware escrito para tower funcione sin cambios en un servidor axum y en un cliente reqwest.

Las lenguas francas: traits que todos hablan

El activo más sutil del ecosistema no son las crates sino ciertos traits que se han vuelto vocabulario universal. serde::Serialize es el caso arquetípico: miles de crates lo implementan para sus tipos, y miles de formatos lo consumen, de modo que cualquier tipo «serde-compatible» habla con cualquier formato «serde-compatible» sin que sus autores se conocieran jamás. Lo mismo hacen Future (que tokio ejecuta pero cualquiera puede producir), el trait Service de tower, o Error de la std. Estas interfaces compartidas son el tejido conectivo: convierten un montón de librerías independientes en un ecosistema donde las piezas encajan.

💡
cargo add y el radar del ecosistema

No memorices versiones: cargo add serde --features derive edita el manifiesto por ti y elige el rango. Para descubrir el canon vivo, blessed.rs cura crates recomendadas por categoría, lib.rs las ordena por relevancia real, y This Week in Rust te mantiene al día. Antes de escribir una utilidad, comprueba si ya existe la crate que todos usan.

Una biblioteca estándar pequeña no es una carencia: es delegar la evolución en quien puede permitírsela

La austeridad de la std de Rust parece, al principio, un defecto frente a lenguajes que traen de fábrica un servidor HTTP y un parser de JSON. Pero es una de las decisiones de diseño más lúcidas del proyecto, y su lógica se revela al notar que estabilidad y evolución son garantías que tiran en direcciones opuestas. Todo lo que entra en la std adquiere un compromiso perpetuo: no podrá romper jamás, porque romper la biblioteca estándar rompería el lenguaje. Esa promesa es exactamente la correcta para lo universal e inmutable —qué es un Vec, cómo funciona Result, qué significa Iterator— pero sería una condena para dominios donde el buen diseño aún se está descubriendo. Una API de serialización o de async metida en la std en su versión temprana quedaría fosilizada en sus primeros errores, incapaz de aprender. Al dejarlas fuera, Rust no abdica de proveerlas: las reubica en un espacio —crates.io— donde el semver permite mayores, la competencia permite que la mejor idea gane, y la iteración permite corregir el rumbo. serde y tokio son hoy magníficas precisamente porque pudieron equivocarse y rehacerse fuera del corsé de la estabilidad eterna. El coste de esta arquitectura es real y no conviene endulzarlo: el recién llegado debe aprender un canon que no viene en la caja, y a veces el ecosistema se fragmenta —hubo, y hay, tensión en torno a qué runtime async es el runtime—. Pero el beneficio estructural lo supera: un núcleo pequeño y eterno sobre el que florece un ecosistema veloz y mejorable, unidos por lenguas francas —los traits compartidos— que hacen que piezas de autores desconocidos entre sí encajen sin fricción. La enseñanza para cualquier diseñador de plataformas es precisa: no metas en tu núcleo estable lo que todavía necesita evolucionar; dale una interfaz común y déjalo crecer fuera. Lo que no puede cambiar y lo que debe cambiar rápido no pueden vivir bajo la misma promesa.

📝
Lo esencial del ecosistema

La std es pequeña a propósito: garantiza estabilidad eterna y delega lo que evoluciona en crates.io. El canon fundacional: serde (serialización), tokio (runtime async), clap (CLI), rayon (paralelismo de datos), reqwest (cliente HTTP) y axum (web). La pila async se apila sobre tokio vía hyper y tower. Los traits compartidos —Serialize, Future, Service, Error— son las lenguas francas que hacen encajar crates de autores distintos. Descubre el canon con blessed.rs, lib.rs y cargo add.

⚔️ Recorre el canon con las manos
  1. Deriva Serialize y Deserialize en un struct, conviértelo a JSON con serde_json y de vuelta. Cambia a formato toml sin tocar el struct: comprueba que el modelo es independiente del formato.
  2. Escribe una CLI con clap usando #[derive(Parser)] y lanza --help: observa cuánto obtienes sin escribirlo.
  3. Toma un cálculo pesado sobre un Vec grande, cambia .iter() por el .par_iter() de rayon y mide la diferencia con time.
  4. Levanta un servidor mínimo con axum y tokio que responda JSON, y consúmelo desde otro binario con reqwest.
  5. Elige una tarea (parsear CSV, medir tiempo, generar UUID) y encuentra en lib.rs o blessed.rs la crate que la comunidad usa, en vez de escribirla tú.