Routing
Pages live in src/pages/. Each file maps directly to a URL:
Export a default React component from any of these files and it becomes a route. Layouts, loading states, and error boundaries follow the same convention.
Special Files
Layouts
Create a layout.tsx file in any directory to wrap all sibling and nested routes.
CraxRouter builds a React Router data router (createBrowserRouter + route.lazy) under the hood. Client-side navigation (<Link>, router.push()) keeps the current page mounted and visible until the next route's module (and loader, if it has one — see Data Fetching) resolves. There's no fallback flash on navigation; that's intentional.
src/pages/loading.tsx is shown only on the initial load of a location — a hard refresh or deep link, where there's no previous page to keep showing. Drop one to use your own fallback for that case; without one, Crax renders a small built-in pulse indicator that respects prefers-reduced-motion.
The layout component must render <Outlet /> to show the active child route:
Navigation
Use the Link component from @crax/router for client-side navigation with prefetching:
All prefetch triggers share one dedupe set keyed by route path, so a link that's hovered, focused, and scrolled into view still only fetches its chunk once.
useRouter
Access router state and navigate programmatically:
Programmatic prefetching
router.push() doesn't prefetch on its own. Import prefetch from @crax/router to warm a route's chunk ahead of a programmatic navigation — it dedupes against the same set the <Link> triggers use:
Route Loaders
Pages can export an async loader to fetch data before the route renders. See Data Fetching for the full pattern.
getRoutes()
getRoutes() enumerates every discovered page route ({ path, filePath, isDynamic }), resolved fresh on each call — useful for SSG/prerender tooling that needs the full route list. See Static Site Generation for an example.
