Tutorial 01: From Zero to Hello Rullst 🚀
What you will build: one complete web application with a typed route and server-rendered HTML. No database account or AI provider is needed. By the end, you will be able to point to the handler that produced the page in your browser.
Choose a different starting path · Next: CLI generators
This tutorial takes a new developer from installing Rust to a running Rullst
web application. It uses the stable 12.0.0 release documented by this site.
Production adoption still needs application review and immutable artifacts;
neither moving main nor merely pinning end-of-life v5 satisfies that
requirement.
1. Install Rust and Cargo
On Linux or macOS, use the official rustup installer:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
On Windows, download rustup from rustup.rs or run:
winget install --id Rustlang.Rustup
Restart the terminal if necessary, then verify the toolchain:
rustc --version
cargo --version
Rullst v12 requires the MSRV recorded in the compatibility policy.
2. Create a project
cargo new my_first_app
cd my_first_app
Every command below must run in this directory, where Cargo.toml lives.
3. Add stable v12
Select its exact crates.io version:
cargo add [email protected]
cargo add tokio --features full
Cargo records the resolved dependency graph in Cargo.lock. Commit that file
for an application so its checkout remains reproducible, and review future
dependency updates before deployment.
Applications that must remain on end-of-life v5 should use its versioned API documentation instead; the v12 API below is intentionally different. That reference preserves the old API, not a promise of ongoing maintenance or a deployment recommendation.
4. Define the first route
Replace src/main.rs with:
use rullst::{html, response::Html, routes, Server};
async fn home() -> Html<String> {
Html(html! {
<div class="min-h-screen bg-slate-900 text-emerald-400 flex flex-col items-center justify-center font-sans">
<h1 class="text-5xl font-extrabold mb-4">"Hello, Rullst! 📜🦀"</h1>
<p class="text-slate-400 text-lg">"Your first typed route is running."</p>
</div>
})
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let app = routes![
get("/" => home)
];
Server::new(app).run(3000).await?;
Ok(())
}
The fallible server startup uses ?, so bind and runtime failures are returned
to the process instead of causing a framework-originated panic.
5. Run the application
Start the server:
cargo run
Open http://localhost:3000. Stop it with Ctrl+C.
Make it yours: change the heading to your project name, restart with
cargo run, and confirm the response changed. The example’s utility class
names do not install Tailwind by themselves; seeing an unstyled page is not a
server failure. Use a generated HTML blueprint for a bundled local stylesheet.
If the port is already occupied, stop the conflicting process you own or change
the .run(3000) port above. Keep the terminal output: it is the first place to
look for a build or startup diagnostic.
6. Continue with the CLI
The v12 CLI can generate complete starters and project modules. While working from a source checkout, install the same revision locally:
git clone --branch main https://github.com/Rullst/Rullst.git
cd Rullst
cargo install --locked --path cargo-rullst
cargo rullst --help
The CLI’s new generator will target the CLI’s framework version. Until v12 is
published, a pre-release CLI built from this checkout emits absolute path
dependencies to that exact checkout, including when invoked elsewhere. Keep the
checkout in place and review those sources before sharing the generated project.
See the CLI reference for every command and boundary.
Key takeaways
- The
rullst::html!macro generates ordinary Rust string-building code and escapes dynamic values. Rendering still performs the allocations/work implied by the generated template. - All boolean HTML attributes inside
html!must be explicitly quoted (e.g.required="true"). - Fallible handlers can return
Result<Response, YourAppError>using an application-defined error that converts the relevant typed framework/domain errors; server startup propagatesServerErrorwith?. - The moving
mainbranch is an integration source, not an immutable release artifact. For reproducible v12 applications, use the exact crates.io version and its matchingv12.0.0tag after the registry publication receipt exists.