Rustango docs
← Erste Schritte

Scaffolding

Rustango hat zwei Ebenen der Codegenerierung — sodass du selten Boilerplate von Hand verdrahtest:

  1. Der Projektgenerator — cargo rustango new erstellt ein komplett neues Projekt aus einer Vorlage.
  2. Projektinterne Generatoren — manage startapp und die manage make:*-Familie fügen Apps, Views, Serializer, Jobs und mehr in einem bestehenden Projekt hinzu.

cargo rustango new scaffoldet ein komplettes, sofort lauffähiges Projekt — Cargo-Manifest, Config-Tiers, Docker, Migrationen und src — mit einem einzigen Befehl

Inhaltsverzeichnis


Den Generator installieren

cargo rustango ist ein Cargo-Unterbefehl. Installiere ihn einmal, global:

cargo install cargo-rustango

Das legt ein cargo-rustango-Binary in deinem PATH ab; Cargo stellt es dann als cargo rustango bereit — ein globaler Befehl, der überall verfügbar ist, auch außerhalb eines Projekts.

Die Version des Generators ist die, die dein Projekt bekommt

cargo rustango new schreibt rustango = "MAJOR.MINOR" in die generierte Cargo.toml — übernommen aus der Version des Generators, nicht aus dem, was gerade auf crates.io am neuesten ist. Welchen Generator du installierst, dessen Version pinnt dein Projekt.

Das ist fast immer das, was du willst, und genau deshalb ist der Installationsbefehl oben ungepinnt: Der neueste Generator schreibt den neuesten Pin, und die beiden können nicht auseinanderdriften.

Wissen solltest du es, wenn du bewusst ein älteres Release willst — um zu einem Projekt zu passen, das bereits darauf läuft, oder um einen Fehlerbericht zu reproduzieren. Pinne den Generator, nicht das Projekt:

cargo install cargo-rustango --version 0.57.0

Welchen du hast, prüfst du mit cargo rustango --version. Später aktualisieren ist derselbe Befehl mit --force, und das wirkt sich nur auf Projekte aus, die du danach generierst — der Pin eines bestehenden Projekts ist eine Zeile in dessen eigener Cargo.toml, die du selbst änderst.


Ein Projekt erstellen: cargo rustango new

cargo rustango new <name> [--template api|fullstack|tenant]
                          [--backend postgres|sqlite|mysql]
                          [--features <liste>]
  • <name> — der Projekt- (und Crate-)Name. Er muss ein gültiger Cargo-Crate-Name sein ([A-Za-z_][A-Za-z0-9_-]*), und das Zielverzeichnis darf noch nicht existieren.
  • --template / -t — welcher Starter gescaffoldet wird (Default: fullstack).
  • --backend / -b — auf welcher Datenbank das Projekt läuft (Default: postgres).
  • --features / -F — zusätzliche Rustango-Features, durch Komma oder Leerzeichen getrennt.
  • --interactive / -i — stattdessen aus Menüs wählen. Ein nacktes cargo rustango new auf einem Terminal macht dasselbe.
  • --help / -h, --version — Verwendung und Version.

Ohne Argumente aufgerufen, fragt es nach:

  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]

Der Wizard setzt genau die Felder, die auch die Flags setzen, und gibt die entsprechende Kommandozeile aus, bevor er irgendetwas schreibt — einmal benutzt, kennst du die Flags, und es gibt nur einen Codepfad, der entscheidet, was ein Projekt enthält. Ohne Terminal (Skript, CI-Job) bricht er mit einer Meldung ab, statt auf eine Antwort zu warten, die niemand geben kann.

Die drei Vorlagen

Jede entspricht einer der drei App-Formen von Rustango:

VorlageWas du bekommstWähle sie, wenn
apiBlankes ORM + Axum, kein AdminJSON-only-Dienste und Microservices
fullstack (Default)ORM + der Auto-AdminEine typische Webapp mit Backoffice
tenantMulti-Tenancy + Operator-Konsole + Apps pro TenantSaaS, das viele isolierte Tenants hostet
cargo rustango new myblog                      # fullstack (the default)
cargo rustango new api_demo  --template api
cargo rustango new shop      --template tenant

Die Datenbank wählen: --backend

cargo rustango new edge --backend sqlite
cargo rustango new shop --backend mysql

--backend entscheidet, was cargo run benutzt, und formt das ganze Projekt passend dazu — die DATABASE_URL in .env.example, die Services in docker-compose.yml, die url in jeder Settings-Stufe und die Startanleitung im README. Nimm sqlite, und es gibt überhaupt keinen Datenbank-Service: sie ist eine Datei neben dem Projekt, die das erste cargo run -- migrate anlegt.

Alle drei Backends bleiben in den generierten [features] verdrahtet, die anderen beiden sind also ein Flag entfernt:

cargo run --no-default-features --features sqlite

Mehr vom Framework einschalten: --features

cargo rustango new saas --template tenant --features csrf,sso,cache-redis

Eine Vorlage schaltet einen sinnvollen Satz ein; --features ergänzt die Opt-ins, die keine von ihnen erreicht:

FeatureWas es hinzufügt
tenancyMulti-Tenancy: Tenant-Registry, Datenbanken pro Tenant, Operator-Konsole
csrfCSRF-Schutz-Middleware für Formular-POSTs
sso / admin-ssoOIDC Single Sign-on, für App-Benutzer / für die Admin-Site
passkeyWebAuthn-/Passkey-Authentifizierung
cache-redis / cache-pageRedis-Cache-Backend / Caching ganzer Seiten
jobs / jobs-postgresHintergrund-Job-Queue, prozessintern / datenbankgestützt und damit neustartfest
schedulerHintergrundaufgaben in festen Intervallen
email-smtpSMTP-Transport für das E-Mail-Framework
mcpModel-Context-Protocol-Server für KI-Agenten
testkit / test_utilsNur-Test-Schema-Builder, Factories und Konstruktoren

cargo rustango new --help gibt diese Liste aus. Backends sind hier nicht gültig — nimm dafür --backend. Eines als Feature zu nennen wird abgelehnt, weil es das Backend des Frameworks festnageln würde, während das eigene Feature des Projekts aus bliebe, und #[derive(Model)] seine Ausgaben an den Features des Projekts ausrichtet.


Was generiert wird

Jede Vorlage schreibt ein in sich geschlossenes Cargo-Projekt:

<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

Ein Binary für alles

src/main.rs ist der einzige Einstiegspunkt. Es startet den HTTP-Server und dispatcht jedes manage-Verb — es gibt keine separate manage.py oder src/bin/manage.rs:

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
}

Also startet cargo run den Server, und cargo run -- <verb> führt Migrationen, Generatoren und den Rest aus.

Wie sich die Vorlagen innerhalb von main.rs / urls.rs unterscheiden:

  • api — kein Admin; urls::api() aggregiert schlicht deine eigenen Routen.
  • fullstack — dieselbe urls.rs, plus das einkompilierte Admin-Feature. Der Admin wird nicht für dich verdrahtet: Nichts Generiertes würde ihn aufrufen, also gibt der Generator keinen admin_router aus. Füge selbst einen hinzu und hänge ihn ein — Erste Schritte, Schritt 11 erklärt es Schritt für Schritt. Nimm rustango::sql::Pool entgegen, damit der Helfer keinen Treiber benennt.
  • tenant — main.rs ergänzt .tenancy(), bedient die Operator-Konsole auf der Apex-Domain und jeden Tenant unter seiner eigenen Subdomain. Die eigenen Tabellen des Frameworks werden beim ersten cargo run -- migrate aus den kompilierten Modellen in einen system/migrations/-Ordner generiert — kein handgeliefertes Bootstrap-JSON, sodass das allererste migrate ohne zusätzliche Einrichtung funktioniert.

Geschichtete Konfiguration

Die Einstellungen laden zuerst config/default.toml, dann config/<RUSTANGO_ENV>_settings.toml darüber. RUSTANGO_ENV ist standardmäßig dev, sodass ein frisch gescaffoldetes cargo run ohne Änderungen funktioniert; setze RUSTANGO_ENV=prod in der Produktion, um prod_settings.toml aufzunehmen.

Erster Lauf

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

Ein Feature-Modul hinzufügen: manage startapp

Scaffolde ein in sich geschlossenes Modul aus zusammengehörigen Modellen, Views und Routen:

cargo run -- startapp blog

Es schreibt src/blog/ mit mod.rs, models.rs (ein Starter-Modell, benannt nach der Singular-Form der App — blog → Blog), views.rs, urls.rs und tests.rs, deklariert dann das Modul in src/main.rs und merged seine Routen in urls::api().

Optionen:

  • --into <dir> — scaffolde unter einem anderen Basisverzeichnis als src/ (z. B. einem Workspace-Member).
  • --with-manage-bin — gib zusätzlich eine bin/manage.rs aus (für Layouts, die ein separates manage-Binary bevorzugen).

Einzelne Dateien generieren: die make:*-Befehle

Innerhalb eines Projekts scaffolden die make:*-Verben jeweils eine Datei. Die vollständige Referenz pro Flag findest du in der manage-CLI-Referenz; die gängigen Formen sind:

BefehlGeneriert
make:viewset <Name> [--model <M>]Ein CRUD-ViewSet
make:serializer <Name> [--model <M>]Ein Serializer zum Formen von Request/Response
make:api_routes <app>Ein API-Routen-Aggregator für eine App
make:form <Name>Ein HTML-Formular mit Validierung
make:job <Name>Ein Handler für einen Hintergrund-Job
make:notification <Name>Eine Mehrkanal-Benachrichtigung
make:middleware <Name>Ein Middleware-Gerüst
make:test <Name>Ein Testmodul mit dem In-process-Testclient
cargo run -- make:viewset PostViewSet --model Post
cargo run -- make:serializer PostSerializer --model Post
cargo run -- make:test post_smoke

Ein typischer Ablauf

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