Andamiaje
Rustango tiene dos capas de generación de código — así rara vez conectas boilerplate a mano:
- El generador de proyectos —
cargo rustango newcrea un proyecto entero nuevo a partir de una plantilla. - Generadores dentro del proyecto —
manage startappy la familiamanage make:*añaden apps, vistas, serializers, jobs y más dentro de un proyecto existente.
Tabla de contenidos
- Instalar el generador
- Crear un proyecto:
cargo rustango new - Qué se genera
- Añadir un módulo de funcionalidad:
manage startapp - Generar archivos sueltos: los comandos
make:* - Un flujo típico
Instalar el generador
cargo rustango es un subcomando de Cargo. Instálalo una vez, de forma global:
cargo install cargo-rustango
Eso coloca un binario cargo-rustango en tu PATH; Cargo lo expone entonces como cargo rustango — un comando global disponible en cualquier parte, incluso fuera de un proyecto.
La versión del propio generador es la que obtiene tu proyecto
cargo rustango new escribe rustango = "MAJOR.MINOR" en el Cargo.toml generado, tomada de la versión del generador, no de lo más reciente que haya en crates.io. Sea cual sea el generador que instales, esa es la versión que fija tu proyecto.
Eso es casi siempre lo que quieres, y por eso el comando de instalación de arriba no lleva versión fijada: el generador más nuevo escribe la fijación más nueva, y los dos no pueden separarse.
Conviene saberlo cuando quieres deliberadamente una versión anterior — para que coincida con un proyecto que ya está en ella, o para reproducir un reporte. Fija el generador, no el proyecto:
cargo install cargo-rustango --version 0.57.0
Comprueba cuál tienes con cargo rustango --version. Actualizarlo más adelante es el mismo comando con --force, y solo afecta a los proyectos que generes después — la fijación de un proyecto existente es una línea en su propio Cargo.toml, que editas tú.
Crear un proyecto: cargo rustango new
cargo rustango new <name> [--template api|fullstack|tenant]
[--backend postgres|sqlite|mysql]
[--features <lista>]
<name>— el nombre del proyecto (y de la crate). Debe ser un nombre de crate de Cargo válido ([A-Za-z_][A-Za-z0-9_-]*), y el directorio de destino no debe existir ya.--template/-t— qué plantilla inicial generar (por defecto: fullstack).--backend/-b— sobre qué base de datos corre el proyecto (por defecto: postgres).--features/-F— funcionalidades extra de Rustango, separadas por comas o espacios.--interactive/-i— elegir desde menús en su lugar. Uncargo rustango newa secas en un terminal hace lo mismo.--help/-h,--version— uso y versión.
Ejecutado sin argumentos, pregunta:
rustango — new project
(enter accepts the default; ctrl-c aborts)
Project name: shop
Template
1) fullstack ORM + auto-admin + forms — the usual starting point (default)
2) api bare ORM + axum, no admin UI — for JSON-only services
3) tenant multi-tenancy: tenant registry + operator console
> 3
Database
1) postgres every feature, including schema-mode tenancy (default)
2) sqlite a file beside the project — no server to run
3) mysql MySQL 8.0+ / MariaDB
> 1
Extra features (numbers, e.g. `1 3 4` — enter for none)
1) csrf CSRF protection middleware for form POSTs
2) sso OIDC single sign-on for application users
…
> 1 2
Same thing without the wizard:
cargo rustango new shop --template tenant --backend postgres --features csrf,sso
Create it? [Y/n]
El asistente fija exactamente los campos que fijan los flags e imprime la línea de comandos equivalente antes de escribir nada — usarlo una vez te enseña los flags, y hay un solo camino de código que decide qué contiene un proyecto. Sin terminal (un script, un job de CI) falla con un mensaje en lugar de esperar una respuesta que nadie va a dar.
Las tres plantillas
Cada una se corresponde con una de las tres formas de app de Rustango:
| Plantilla | Lo que obtienes | Recurre a ella cuando |
|---|---|---|
api | ORM + Axum a secas, sin admin | Servicios solo-JSON y microservicios |
fullstack (por defecto) | ORM + el auto-admin | Una app web típica con back-office |
tenant | Multi-tenancy + consola de operador + apps por tenant | SaaS que aloja muchos tenants aislados |
cargo rustango new myblog # fullstack (the default)
cargo rustango new api_demo --template api
cargo rustango new shop --template tenant
Elegir la base de datos: --backend
cargo rustango new edge --backend sqlite
cargo rustango new shop --backend mysql
--backend decide qué usa cargo run, y da forma a todo el proyecto en consecuencia — la DATABASE_URL de .env.example, los servicios de docker-compose.yml, la url de cada nivel de configuración y las instrucciones de arranque del README. Elige sqlite y no hay servicio de base de datos alguno: es un fichero junto al proyecto, creado por el primer cargo run -- migrate.
Los tres backends siguen cableados en los [features] generados, así que los otros dos quedan a un flag de distancia:
cargo run --no-default-features --features sqlite
Encender más del framework: --features
cargo rustango new saas --template tenant --features csrf,sso,cache-redis
Una plantilla enciende un conjunto razonable; --features añade las opciones que ninguna de ellas alcanza:
| Funcionalidad | Qué añade |
|---|---|
tenancy | Multi-tenancy: registry de tenants, bases por tenant, consola de operador |
csrf | Middleware de protección CSRF para POST de formularios |
sso / admin-sso | Inicio de sesión único OIDC, para usuarios de la app / para el sitio de admin |
passkey | Autenticación WebAuthn / passkey |
cache-redis / cache-page | Backend de caché Redis / caché de páginas completas |
jobs / jobs-postgres | Cola de trabajos en segundo plano, en proceso / respaldada por la base de datos y por tanto resistente a reinicios |
scheduler | Tareas en segundo plano a intervalos fijos |
email-smtp | Transporte SMTP para el framework de email |
mcp | Servidor Model Context Protocol para agentes de IA |
testkit / test_utils | Constructores de esquema, factorías y constructores solo para tests |
cargo rustango new --help imprime esta lista. Los backends no son válidos aquí — usa --backend. Nombrar uno como funcionalidad se rechaza, porque fijaría el backend del framework mientras la funcionalidad propia del proyecto quedaría apagada, y #[derive(Model)] alinea lo que emite con las funcionalidades del proyecto.
Qué se genera
Cada plantilla escribe un proyecto de Cargo autocontenido:
<name>/
Cargo.toml # the rustango dependency + features for this template
.env.example # copy to .env (DATABASE_URL, RUSTANGO_SESSION_SECRET, …)
.gitignore
rust-toolchain.toml # selects the `stable` toolchain + rustfmt/clippy/rust-analyzer
docker-compose.yml # a Postgres service to develop against
Dockerfile # production image
README.md
config/
default.toml # settings shared across every environment
dev_settings.toml # per-tier overrides …
staging_settings.toml
prod_settings.toml
migrations/ # JSON migration files (committed to git)
src/
main.rs # the single binary — HTTP server + every manage verb
models.rs # your #[derive(Model)] structs
views.rs # request handlers ("views")
urls.rs # pub fn api() -> Router that aggregates your routes
Un binario para todo
src/main.rs es el único punto de entrada. Arranca el servidor HTTP y despacha cada verbo de manage — no hay un manage.py ni un src/bin/manage.rs aparte:
mod models;
mod urls;
mod views;
#[rustango::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let _ = dotenvy::dotenv();
rustango::manage::Cli::new()
.api(urls::api())
.with_welcome() // friendly `/` page until you add a root handler
.with_health() // /health + /ready endpoints (fullstack & tenant)
.run()
.await
}
Así que cargo run arranca el servidor, y cargo run -- <verb> ejecuta migraciones, generadores y lo demás.
Cómo difieren las plantillas dentro de main.rs / urls.rs:
- api — sin admin;
urls::api()simplemente agrega tus propias rutas. - fullstack — el mismo
urls.rs, más la funcionalidad de admin compilada dentro. El admin no queda cableado por ti: nada de lo generado lo llamaría, así que el generador no emite ningúnadmin_router. Añade uno tú mismo y anídalo — Primeros pasos, Paso 11 lo explica con detalle. Recibe unrustango::sql::Poolpara que el ayudante no nombre ningún driver. - tenant —
main.rsañade.tenancy(), sirviendo la consola de operador en el dominio ápice y cada tenant bajo su propio subdominio. Las propias tablas del framework se generan en una carpetasystem/migrations/a partir de los modelos compilados en el primercargo run -- migrate— sin JSON de bootstrap entregado a mano, así que la primerísima migración funciona sin configuración adicional.
Configuración por capas
Los ajustes cargan primero config/default.toml, luego config/<RUSTANGO_ENV>_settings.toml encima. RUSTANGO_ENV es dev por defecto, así que un cargo run recién generado funciona sin ediciones; establece RUSTANGO_ENV=prod en producción para recoger prod_settings.toml.
Primera ejecución
cd <name>
cp .env.example .env
docker compose up -d # start Postgres
cargo run -- migrate # apply migrations
cargo run # serve
cargo run -- --help # see every manage verb
Añadir un módulo de funcionalidad: manage startapp
Genera un módulo autocontenido de modelos, vistas y rutas relacionados:
cargo run -- startapp blog
Escribe src/blog/ conteniendo mod.rs, models.rs (un modelo inicial nombrado según la forma singular de la app — blog → Blog), views.rs, urls.rs y tests.rs, luego declara el módulo en src/main.rs y fusiona sus rutas en urls::api().
Opciones:
--into <dir>— genera el andamiaje bajo un directorio base distinto desrc/(p. ej. un miembro del workspace).--with-manage-bin— emite además unbin/manage.rs(para diseños que prefieren un binario de manage aparte).
Generar archivos sueltos: los comandos make:*
Dentro de un proyecto, los verbos make:* generan el andamiaje de un archivo cada vez. La referencia completa por flag vive en la referencia de la CLI de manage; las formas comunes son:
| Comando | Genera |
|---|---|
make:viewset <Name> [--model <M>] | Un ViewSet CRUD |
make:serializer <Name> [--model <M>] | Un serializer para dar forma a request/response |
make:api_routes <app> | Un agregador de rutas de API para una app |
make:form <Name> | Un formulario HTML con validación |
make:job <Name> | Un handler de job en segundo plano |
make:notification <Name> | Una notificación multicanal |
make:middleware <Name> | Un esqueleto de middleware |
make:test <Name> | Un módulo de pruebas usando el cliente de pruebas en el mismo proceso |
cargo run -- make:viewset PostViewSet --model Post
cargo run -- make:serializer PostSerializer --model Post
cargo run -- make:test post_smoke
Un flujo típico
cargo rustango new myblog # 1. scaffold the project
cd myblog
cargo run -- startapp blog # 2. add a feature module
# …add fields to src/blog/models.rs…
cargo run -- makemigrations # 3. generate a migration
cargo run -- migrate # 4. apply it
cargo run -- make:viewset PostViewSet --model Post # 5. expose a JSON API
cargo run # 6. serve
