Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Tutorial 30: Axum Escape-Hatch Snapshot (cargo rullst eject) 🔓

eject generates a minimal Axum/Tokio entry point that can begin a manual migration away from Rullst’s server wrapper. It does not statically expand macros, copy the application’s route graph, convert middleware, or remove Rullst dependencies automatically.


Step 1: Generate a separate starting point

cargo rullst eject

The default output is src/ejected_main.rs; the existing src/main.rs remains unchanged. The generated server contains only a demonstration root route:

use axum::{routing::get, Router};
use tokio::net::TcpListener;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let app = Router::new()
        .route("/", get(|| async { "Ejected Axum server" }));
    let listener = TcpListener::bind("127.0.0.1:3000").await?;
    axum::serve(listener, app).await?;
    Ok(())
}

Move application routes one bounded group at a time and retain equivalent security headers, CSRF/CORS/WAF order, limits, telemetry, graceful shutdown, health behavior, state, and authorization tests.


Step 2: Treat --force as a deliberate replacement

cargo rullst eject --force

The hardened command first preserves the original entry point as src/main.rs.rullst-backup and refuses to overwrite an existing backup. Keep a normal version-control commit as the authoritative recovery path. Custom output paths are restricted to relative Rust files under src/ and existing targets are not overwritten implicitly.


Key takeaways

  • Ejection is a migration aid, not a semantics-preserving compiler transform.
  • The application remains responsible for dependency cleanup and replacements for ORM, auth, queues, Studio, Nexus, Capital, AI, and other selected crates.
  • Run cargo fmt, strict Clippy, the complete test suite, and application security/operational checks after every migrated route group.