TanStack Router brings 100% type-safe routing to React. Its API for search params, loaders, and nested layouts is far more powerful than React Router.
Type-Safe Route Definitions
import { createFileRoute } from "@tanstack/react-router"
import { z } from "zod"
export const Route = createFileRoute("/products")({
validateSearch: z.object({
page: z.number().default(1),
sort: z.enum(["name", "price", "date"]).default("date"),
q: z.string().optional()
}),
loaderDeps: ({ search }) => ({ page: search.page, sort: search.sort }),
loader: async ({ deps }) => {
return fetchProducts({ page: deps.page, sort: deps.sort })
},
component: ProductsPage
})
function ProductsPage() {
const products = Route.useLoaderData()
const search = Route.useSearch()
const navigate = Route.useNavigate()
return (
<div>
<select
value={search.sort}
onChange={(e) => navigate({ search: { sort: e.target.value } })}
>
<option value="name">Name</option>
<option value="price">Price</option>
<option value="date">Date</option>
</select>
{products.map(p => <ProductCard key={p.id} product={p} />)}
</div>
)
}
Type-Safe Links
import { Link } from "@tanstack/react-router"
// TypeScript knows all valid routes and their params!
<Link to="/products" search={{ page: 1, sort: "price" }}>
Products
</Link>
<Link to="/products/$productId" params={{ productId: "123" }}>
Product Detail
</Link>
// Type error! "invalid" is not a valid sort option
<Link to="/products" search={{ sort: "invalid" }}>
Oops
</Link>
Route Context & Auth
// routes/__root.tsx
export const Route = createRootRouteWithContext<{
auth: AuthContext
queryClient: QueryClient
}>()({
component: RootComponent
})
// routes/_authenticated.tsx
export const Route = createFileRoute("/_authenticated")({
beforeLoad: ({ context }) => {
if (!context.auth.isAuthenticated) {
throw redirect({ to: "/login" })
}
}
})
// routes/_authenticated/dashboard.tsx
export const Route = createFileRoute("/_authenticated/dashboard")({
loader: async ({ context }) => {
return context.queryClient.ensureQueryData(dashboardQuery())
},
component: Dashboard
})
Pending UI & Streaming
export const Route = createFileRoute("/slow-page")({
loader: () => fetchSlowData(),
pendingComponent: () => <FullPageSpinner />,
pendingMs: 200, // Show pending after 200ms
pendingMinMs: 500 // Show for at least 500ms
})
Key Takeaways
- 100% type-safe routes, params, search params, loaders
- File-based routing with code generation
- Search param validation with Zod
- Route context for auth and dependency injection
- Pending UI with configurable timings
- Preloading on hover for instant navigation
Explore TanStack Router docs for the complete API.
Building web scrapers or data pipelines? Check out my Apify actors for ready-made solutions, or email spinov001@gmail.com for custom development.
Top comments (0)