Rustango docs
← Primeros pasos

Andamiaje

Rustango tiene dos capas de generación de código — así rara vez conectas boilerplate a mano:

  1. El generador de proyectos — cargo rustango new crea un proyecto entero nuevo a partir de una plantilla.
  2. Generadores dentro del proyecto — manage startapp y la familia manage make:* añaden apps, vistas, serializers, jobs y más dentro de un proyecto existente.

cargo rustango new genera un proyecto completo y listo para ejecutar — manifiesto de Cargo, niveles de configuración, Docker, migraciones y src — en un solo comando

Tabla de contenidos


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. Un cargo rustango new a 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:

PlantillaLo que obtienesRecurre a ella cuando
apiORM + Axum a secas, sin adminServicios solo-JSON y microservicios
fullstack (por defecto)ORM + el auto-adminUna app web típica con back-office
tenantMulti-tenancy + consola de operador + apps por tenantSaaS 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:

FuncionalidadQué añade
tenancyMulti-tenancy: registry de tenants, bases por tenant, consola de operador
csrfMiddleware de protección CSRF para POST de formularios
sso / admin-ssoInicio de sesión único OIDC, para usuarios de la app / para el sitio de admin
passkeyAutenticación WebAuthn / passkey
cache-redis / cache-pageBackend de caché Redis / caché de páginas completas
jobs / jobs-postgresCola de trabajos en segundo plano, en proceso / respaldada por la base de datos y por tanto resistente a reinicios
schedulerTareas en segundo plano a intervalos fijos
email-smtpTransporte SMTP para el framework de email
mcpServidor Model Context Protocol para agentes de IA
testkit / test_utilsConstructores 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ún admin_router. Añade uno tú mismo y anídalo — Primeros pasos, Paso 11 lo explica con detalle. Recibe un rustango::sql::Pool para que el ayudante no nombre ningún driver.
  • tenant — main.rs añ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 carpeta system/migrations/ a partir de los modelos compilados en el primer cargo 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 de src/ (p. ej. un miembro del workspace).
  • --with-manage-bin — emite además un bin/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:

ComandoGenera
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