How this site is built
Most “learn X” sites are built in something else. This one is built in X: Rust, from the HTTP handler down to the SQL driver. This page is a guided tour of the actual code running right now. If you’re learning Rust to build real things, this is a real thing.
The shape of it
Browser ──HTTP──▶ Fly.io machine (Rust binary)
│ axum router + Leptos SSR
│ ├─ renders HTML on the server
│ ├─ ships a WebAssembly bundle that "hydrates" it
│ └─ #[server] functions ──sqlx──▶ Postgres
Browser ──direct──▶ play.rust-lang.org (runs your code)
There is no JavaScript framework here. The interactivity you see (the counter, the code runner) is Rust compiled to WebAssembly.
One language, both sides
The frontend is Leptos, a Rust UI framework with fine-grained reactivity. The same App component runs in two places:
- On the server, it renders to an HTML string (fast first paint, real SEO).
- In the browser, the same code (compiled to WebAssembly) “hydrates” that HTML, attaching event listeners so it becomes interactive.
You write it once, in Rust. The build produces two artifacts from one crate: a native server binary and a .wasm file. Cargo feature flags (ssr vs hydrate) decide what compiles where, so server-only code like the database driver never reaches the browser.
The full-stack seam: #[server]
The magic glue is one macro. Write a function, annotate it, and call it from the UI:
#[server]
pub async fn record_completion(slug: String) -> Result<i64, ServerFnError> {
let pool = use_context::<sqlx::PgPool>()?; // injected at startup
let count = sqlx::query_scalar!(
"INSERT INTO lesson_stats (slug, completion_count) VALUES ($1, 1)
ON CONFLICT (slug) DO UPDATE
SET completion_count = lesson_stats.completion_count + 1
RETURNING completion_count",
slug
).fetch_one(&pool).await?;
Ok(count)
}
On the server, this body runs. In the browser, the macro replaces it with a network call that serializes the arguments, hits an endpoint, and deserializes the result, type-checked end to end, because both sides share the same Rust types. The counter on the home page is exactly this function talking to Postgres.
Notice query_scalar!. That’s not a string the database sees at runtime and hopes for the best; sqlx connects to Postgres at compile time and verifies the SQL and its types. A typo in a column name is a build error, not a 2 a.m. page.
The code runner
When you press Run on a lesson, a #[server] function proxies your code to the official Rust Playground’s /execute API and streams the output back. The Playground does the compiling; we do the plumbing, in about forty lines of Rust.
Shipping it
Every git push to main triggers GitHub Actions, which runs clippy, then builds a multi-stage Docker image (cargo-leptos compiles the server and the wasm), and deploys it to Fly.io. Postgres runs as a second Fly app; the binary connects over a private network. There is no deploy button: there’s git push.
Why Rust earned each layer
None of this is Rust for its own sake. Each layer chose it for a concrete payoff you can read in the code:
- One language, both sides. The same Leptos components render on the server and hydrate in the browser as WebAssembly. There is no second language, and no API schema to drift out of sync.
- A single, light binary.
cargocompiles the whole server to one native executable that ships in a small container and boots fast, with no runtime or interpreter to install beside it. - The database cannot lie to you.
sqlxchecks every query against Postgres at compile time, so a renamed column is a build error, not a 2 a.m. page. - Safety and speed, without picking one. No garbage collector, no data races, performance in C’s league. The same properties that put Rust in kernels, CLIs, and Cloudflare’s proxies (see where Rust wins) are the ones serving this page.
- The compiler as a tireless reviewer. Much of this was written with an AI agent, and the borrow checker and type system caught the slips before they shipped. That is the site’s whole thesis, applied to its own construction.
The AI tutor
The AI tutor is live. Ask a question and a Rust #[server] function runs a retrieval pipeline: your question is embedded, the closest passages from a curated Rust corpus are pulled from Qdrant (a vector database written in Rust), re-ranked by a unit-tested lifecycle policy, and Claude answers from what was retrieved, citing its sources and steered to admit what it does not know rather than guess.
The AI models themselves (Claude for answers, an embedding model for retrieval) are services the site consumes, the way a site consumes a map provider or a payments processor. They are not part of the stack any more than the videos are part of YouTube’s stack. The stack is every line of executable code this site owns, and that is Rust end to end: the server, the pipeline, the retrieval, the re-ranker, the math, the clients.
What grew after launch
The page above describes the founding skeleton. The systems that grew around it, each with its own honest seams:
The Forge (tools/forge) compiles every example on this site against the newest stable rustc, in CI, weekly and on every push. Deliberately broken walkthroughs must fail with the exact documented error; the stderr you see in lessons is captured from the real compiler, never typed by hand. The result bakes into the binary as constants and surfaces on /status.
The content pipeline runs daily as a one-off Fly machine on the deployed image: it fetches curated YouTube channels over plain RSS, classifies each video onto the skill tree with a schema-constrained Haiku call (the allowed node list is generated from the curriculum at compile time, so it cannot drift), writes short learner explainers with Sonnet (content-hash cached, bounded per run), embeds everything into Qdrant, and writes the weekly learner digest.
Retrieval has a lifecycle: every chunk carries its class and age, and a plain Rust re-ranker (unit-tested, constants in the open) damps old videos and news without ever deleting knowledge. Lessons and error walkthroughs never decay, because the Forge re-verifies them instead.
The observatory (/map) projects every chunk to two dimensions with power-iteration PCA written from scratch in this repo, no numerics crate: the implicit-covariance trick is about sixty lines and doubles as teaching material. The same batch computes related rails for every node and a coverage-gap report: the site telling its author what to write next.
The Anvil (/anvil) and the smith’s mark close the loop: a weekly broken program with its real error, repaired in the browser and verified by the playground; progress is earned only by verified actions and persists through an anonymous recovery code. And for machines rather than people, the same corpus is exposed as a read-only MCP server at /mcp.
Every one of those systems was built by an AI agent working against this repository’s gates: the build that fails on a banned character, the drift checker that fails on a stale doc path, the Forge that fails on an example that stopped compiling. The gates are the pedagogy, applied to the site itself.