# nextrs
A Next.js-style routing framework for Rust, built on [Axum](https://docs.rs/axum) and [Askama](https://docs.rs/askama).
File-based routes with `page` / `layout` / `loading` / `middleware` / `route` conventions, HTTP-level streaming for the loading shell, an optional typed-client pipeline (OpenAPI → React Query hooks), and optional React `page.tsx` pages whose data the server can seed into the client cache. Deploys to Vercel as a single Rust function, or runs anywhere as a normal Axum app.
```text
app/
├── layout.{rs,html} root layout, wraps every route
├── page.{rs,html,tsx} / — .rs/.html server-rendered, or .tsx React
├── middleware.rs request guard, composed root-to-leaf
├── api/ping/route.rs /api/ping — typed HTTP handlers (get/post/…)
└── dashboard/
├── loading.{rs,html} streamed shell shown while the page resolves
└── page.{rs,html} /dashboard
```
Each directory is a URL segment; each filename is a convention slot. `.rs` wins when both `.rs` and `.html` exist. Adding a route is just adding a file — a build-time codegen step (the `build` feature, called from your `build.rs`) discovers the tree and wires the router, with no hand-written `mod` declarations or registry constructors.
## Quick start
```toml
[dependencies]
nextrs = "0.3"
axum = "0.8"
tokio = { version = "1", features = ["full"] }
askama = "0.15"
[build-dependencies]
nextrs = { version = "0.3", features = ["build"] }
```
```rust,ignore
// build.rs
fn main() {
nextrs::build::emit_registry("app", "src/main.rs", "nextrs_routes.rs").unwrap();
}
```
```rust,ignore
// src/main.rs
include!(concat!(env!("OUT_DIR"), "/nextrs_routes.rs"));
#[tokio::main]
async fn main() {
let app = nextrs::router::build_router(generated_registry());
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
}
```
## Features
- **`build`** — the build-script codegen (`nextrs::build`, `nextrs::docs`): route discovery, the generated registry, and a markdown→docs+llms.txt pipeline. Depend on it under `[build-dependencies]` only.
- **`tsx`** — build-time bundling of React `page.tsx` entries via [rolldown](https://crates.io/crates/rolldown). Heavy build-dependency tree; enable only if you use `.tsx` pages.
- **`vercel`** — `nextrs::vercel::StreamingVercelLayer`, a drop-in replacement for the upstream Vercel layer that preserves `text/html` streaming.
## Streaming
A route with a `loading` slot streams the shell first and swaps in the page when its handler resolves — one HTTP response, no client framework:
```text
[layout-open]
<div id="__nx_slot__"> …loading… </div> ← arrives at TTFB
<template id="__nx_page__"> …page… </template> ← arrives when the handler resolves
<script> </script>
[layout-close]
```
## Status
Pre-1.0 — the API will change. See the [repository](https://github.com/drewhirschi/nextrs) for the full docs, examples (including a React + server-seeded-cache todo app), and design notes.
## License
Apache-2.0