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

Rendering

Plinth builds the same Leptos app for several rendering targets. The route-level source of truth is app_routes() in crates/client/src/app.rs; the table below documents the default all-bricks build.

Route Modes

RouteModeWhy
/Streaming SSR, SsrMode::OutOfOrderThe home page aggregates multiple bricks, so the shell can stream while slower sections resolve.
/aboutSSG, SsrMode::StaticSite content changes only when an admin publishes the about key.
/supportSSG, SsrMode::StaticSite content changes only when an admin publishes the support key.
/postsSSG, SsrMode::StaticBlog index content changes at publish cadence.
/posts/:slugSSG, SsrMode::Static with prerendered slugsPublished posts are addressable static content.
/posts/tag/:tagSSG, SsrMode::Static with prerendered tag names and slugsTag pages change when posts or tags are published.
/seriesSSG, SsrMode::StaticSeries membership changes at blog publish cadence.
/series/:slugSSG, SsrMode::Static with prerendered series slugsSeries pages are derived from published posts.
/projectsSSG, SsrMode::StaticPortfolio index content changes at publish cadence.
/projects/:slugSSG, SsrMode::Static with prerendered project slugsPortfolio entries are stable published content.
/activityDynamic SSR, SsrMode::OutOfOrderActivity is ranked and refreshed at request time.
/activity/:idDynamic SSR, SsrMode::OutOfOrderIndividual activity entries may refresh forge metadata.
/todosDynamic SSR, SsrMode::OutOfOrderTodo ordering and completion state are ranked/user-curated dynamic data.
/todos/tag/:tagDynamic SSR, SsrMode::OutOfOrderTagged todo lists are request-time ranked views.
/todos/:slugDynamic SSR, SsrMode::OutOfOrderTodo detail pages expose mutable state.

Custom builds with one or more bricks disabled keep the static site-content routes and omit the disabled brick routes at compile time.

Decision Rule

Use static generation for publish-cadence content: site pages, blog posts, series, and portfolio entries. Use streaming SSR for multi-source aggregate pages where independent sections can resolve at different speeds. Use dynamic SSR for user-curated, ranked, or externally refreshed data. Use islands for interactive widgets that need client behavior without hydrating the whole app. Use the CSR build for serverless or static-host deployments where a separate Plinth API server supplies content.

Islands Boundary

The SSR/hydrate build enables Leptos islands. The app shell and page bodies are server-rendered, while the interactive header boundary hydrates on the client: Header is an island in non-CSR islands builds, and ThemeToggle is always an island. This keeps the mobile navigation toggle and theme persistence interactive without hydrating read-only content pages.

Static Regeneration

Static routes use Leptos StaticRoute::regenerate streams. Admin publish paths send invalidation events after a successful write:

Admin writeInvalidated static routes
Blog publish, update, delete, or tag change/posts, matching /posts/:slug, matching /posts/tag/:tag, /series, and matching /series/:slug when a series is involved
Portfolio publish/projects and matching /projects/:slug
Site content publishMatching site-content route such as /about or /support

The invalidation signal is narrow: request-time routes do not participate in static regeneration because they are rendered dynamically.

Build Targets

Build the default SSR/islands target with:

cargo leptos build

This produces the server binary and the browser WASM/CSS assets for the normal deployment package. The same route table controls server rendering and the hydration boundary.

Build the client-only CSR target with:

nix build .#plinth-csr

The CSR package emits static files only. It renders routes in the browser and uses public GET /api/* endpoints instead of Leptos server functions. Use it for static previews or static hosting paired with a separate Plinth API server; prefer the default SSR package when the deployment should serve rendered HTML, feeds, admin APIs, and proxied images from one process.

WASM Safety

Server-only dependencies stay behind the ssr feature. The client crate is included with default-features = false, and browser builds must not pull in Axum, Tokio server actors, SQLx, forge refresh code, or other server-only runtime dependencies. Data that the browser needs comes through shared types, hydrated resources, server functions in SSR builds, or public REST calls in the CSR build.