A production-ready Leptos/Axum template with SSR + hydration, auth, SQLx migrations, Redis, observability, Docker/CI, and a Tailwind-powered UI.
- Rust toolchain (MSRV 1.88.0) and
wasm32-unknown-unknowntarget:rustup target add wasm32-unknown-unknown - Node.js (for Tailwind; optional if you rely on cargo-leptos to run Tailwind CLI)
- Docker + Docker Compose (for Postgres/Redis in dev)
cargo-leptosandwasm-bindgenCLIs installed (binaries are already in~/.cargo/binfrom this setup; install otherwise via the Leptos docs)
cp .env.example .env # fill secrets: JWT/refresh/CSRF (lengths enforced)
docker compose -f infra/docker/compose.dev.yml up -d db redis
cargo leptos watch -- --bin server # hot reload (SSR + front)Open http://localhost:3000. Auth flow uses cookies (domain must match COOKIE_DOMAIN in .env).
make dev— compose (db/redis) + cargo-leptos watchmake migrate— run SQLx migrationsmake seed— seed data via CLImake lint— fmt + clippymake test— cargo testmake build— release buildmake docker— build Docker image
Tailwind (if you want manual control):
npx tailwindcss -i assets/tailwind.css -c tailwind.config.js -o target/site/pkg/app.css --watchSee .env.example. Required:
JWT_SECRET,REFRESH_TOKEN_SECRET(>=32 chars),CSRF_SECRET(>=16 chars)DATABASE_URL,REDIS_URLAPP_BASE_URL,COOKIE_DOMAINRUST_LOG(e.g.info,server=debug) Optional observability:OTEL_EXPORTER_OTLP_ENDPOINT(set only if collector is running to avoid connection warnings).
Workspace crates:
crates/app— Leptos UI (SSR + hydrate)crates/server— Axum SSR server, API, middlewarecrates/shared— DTO, config, errors, typescrates/domain— auth/domain logiccrates/db— SQLx repositories, migrationscrates/cli— admin CLI (migrate, seed, users)
Migrations live in migrations/. Run locally:
make migrateCI runs migrations against ephemeral Postgres.
- Dev compose:
infra/docker/compose.dev.yml(Postgres + Redis) - Dockerfile:
infra/docker/Dockerfile - GitHub Actions workflow runs fmt, clippy (
-D warnings), tests, and migrations.
- If you see
OpenTelemetry ... Connection refused, remove/clearOTEL_EXPORTER_OTLP_ENDPOINTunless a collector is running. - Ensure
COOKIE_DOMAINmatches the host you open (e.g. uselocalhostnot127.0.0.1if the cookie domain islocalhost).
If you use Nix, you can get a reproducible dev environment with pinned Rust + WASM target + tooling:
nix develop
npm ci
make devRelease build + run:
cargo leptos build --release --precompress --split
cargo run -p server --release