A production-minded cargo-generate template for server-rendered Rust web applications. It starts with a working Hello World page while establishing clear boundaries between HTTP handling, HTML presentation, and browser-side enhancement.
| Layer | Technology | Purpose |
|---|---|---|
| HTTP server | Axum 0.8 | Routing, extractors, middleware, typed responses |
| HTML rendering | Askama 0.16 | Compile-time checked, auto-escaped server templates |
| Navigation | Turbo 8 | Drive navigation, Frames, and Streams |
| Browser behavior | Stimulus 3 | Small controllers for browser-only interaction |
| Frontend language | TypeScript | Strictly typed Stimulus controllers and asset entrypoints |
| Asset build | Vite | Bundles Turbo, Stimulus, TypeScript, and CSS |
| Runtime and tasks | mise | Pins Rust, Node.js, and npm and exposes one command surface |
The generated application renders its core content on the server. Turbo improves navigation and partial updates, while Stimulus is reserved for transient browser behavior. It does not create a second client-side application or duplicate server state in the browser.
Install cargo-generate and mise, then run the template from the directory that should contain the new project:
cargo install cargo-generate --version 0.23.13 --locked
cd ~/Workspace
cargo generate --path ~/Workspace/rust-web-stack --name my-web-appAfter this repository is published, replace the local path with its Git URL:
cd ~/Workspace
cargo generate --git <repository-url> --name my-web-appcargo-generate converts the project name to kebab-case and creates a new Git repository without overwriting an existing directory.
cd ~/Workspace/my-web-app
mise trust mise.toml
mise install
mise run setup
mise run checkRun the server and frontend asset watcher in separate terminals:
mise run dev:servermise run dev:webOpen http://127.0.0.1:3000. The page demonstrates:
- a full HTML document rendered by Axum and Askama;
- a Turbo Frame updated by the
/helloendpoint; - a strictly typed Stimulus controller;
- CSS and TypeScript built by Vite and served by Axum.
.
├── Cargo.toml
├── mise.toml
├── src/
│ ├── main.rs
│ ├── error.rs
│ └── response.rs
├── templates/
│ ├── layouts/
│ ├── pages/
│ └── fragments/
├── client/
│ ├── src/
│ │ ├── controllers/
│ │ └── styles/
│ ├── package.json
│ └── vite.config.ts
└── docs/
├── axum-askama.md
└── hotwire.md
The two documents under docs/ define the intended development conventions. Read them before adding routes, templates, Frames, Streams, or Stimulus controllers.
| Command | Description |
|---|---|
mise run setup |
Install pinned frontend dependencies |
mise run fmt |
Check Rust formatting |
mise run lint |
Run Clippy with warnings denied |
mise run test:rust |
Run Rust tests |
mise run test:web |
Type-check and build frontend assets |
mise run check |
Run the complete verification suite |
mise run dev:server |
Start the Axum server |
mise run dev:web |
Watch TypeScript and CSS assets |
cargo-generate uses Liquid syntax, while Askama also uses {{ ... }} and {% ... %}. To keep the two template languages isolated, cargo-generate.toml uses an explicit include list. Only Cargo, mise, and npm metadata files are processed by Liquid; Askama templates and documentation are copied byte-for-byte.
Keep documentation filenames stable and update them in place. Preserve typed Rust errors at boundaries, and do not make business, retry, or backoff decisions by comparing raw error strings.