Leptos is a full-stack Rust framework with fine-grained reactivity, SSR, and hydration. Write your frontend AND backend in Rust — with a React-like component model that's faster than virtual DOM.
Why Leptos?
- Fine-grained reactivity — no virtual DOM diffing, signals update exactly what changed
- Full-stack — SSR, hydration, server functions — all in Rust
- WASM frontend — compiles to WebAssembly for near-native speed
- Type-safe — share types between server and client
Quick Start
cargo install cargo-leptos
cargo leptos new --git leptos-rs/start
cd myapp
cargo leptos watch
Components and Signals
use leptos::*;
#[component]
fn Counter() -> impl IntoView {
let (count, set_count) = create_signal(0);
view! {
<div>
<p>"Count: " {count}</p>
<button on:click=move |_| set_count.update(|n| *n += 1)>
"Increment"
</button>
</div>
}
}
Derived Signals
#[component]
fn App() -> impl IntoView {
let (count, set_count) = create_signal(0);
let doubled = move || count() * 2;
let is_even = move || count() % 2 == 0;
view! {
<p>"Count: " {count}</p>
<p>"Doubled: " {doubled}</p>
<p>{move || if is_even() { "Even" } else { "Odd" }}</p>
}
}
Server Functions
#[server(GetUsers, "/api")]
pub async fn get_users() -> Result<Vec<User>, ServerFnError> {
let users = db::get_all_users().await?;
Ok(users)
}
#[component]
fn UserList() -> impl IntoView {
let users = create_resource(|| (), |_| get_users());
view! {
<Suspense fallback=move || view! { <p>"Loading..."</p> }>
{move || users.get().map(|result| match result {
Ok(users) => view! {
<ul>
{users.into_iter().map(|u| view! {
<li>{u.name}</li>
}).collect_view()}
</ul>
}.into_view(),
Err(e) => view! { <p>{e.to_string()}</p> }.into_view(),
})}
</Suspense>
}
}
Forms and Actions
#[server(AddTodo, "/api")]
pub async fn add_todo(title: String) -> Result<(), ServerFnError> {
db::insert_todo(&title).await?;
Ok(())
}
#[component]
fn TodoForm() -> impl IntoView {
let add = create_server_action::<AddTodo>();
view! {
<ActionForm action=add>
<input type="text" name="title" />
<button type="submit">"Add Todo"</button>
</ActionForm>
}
}
Routing
use leptos_router::*;
#[component]
fn App() -> impl IntoView {
view! {
<Router>
<nav>
<A href="/">"Home"</A>
<A href="/users">"Users"</A>
</nav>
<Routes>
<Route path="/" view=Home />
<Route path="/users" view=UserList />
<Route path="/users/:id" view=UserDetail />
</Routes>
</Router>
}
}
Building data-intensive Rust apps? Check out my Apify actors for web scraping, or email spinov001@gmail.com for custom Rust development.
Leptos, Yew, or Dioxus — which Rust frontend framework do you prefer? Comment below!
Top comments (0)