DEV Community

Alex Spinov
Alex Spinov

Posted on

TanStack Router Has a Free API That Makes React Routing Type-Safe

TanStack Router is the first fully type-safe router for React. Search params, path params, loaders — everything is typed end-to-end.

Type-Safe Route Tree

import { createRootRoute, createRoute, createRouter } from "@tanstack/react-router";

const rootRoute = createRootRoute({ component: RootLayout });

const indexRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: "/",
  component: HomePage,
});

const productRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: "/products/$productId",
  // Loader runs before render — type-safe!
  loader: async ({ params }) => {
    return fetchProduct(params.productId); // params.productId is typed as string
  },
  component: ProductPage,
});

function ProductPage() {
  const { productId } = productRoute.useParams(); // Typed!
  const product = productRoute.useLoaderData();    // Typed!
  return <div>{product.title}</div>;
}
Enter fullscreen mode Exit fullscreen mode

Type-Safe Search Params

import { z } from "zod";

const productsRoute = createRoute({
  getParentRoute: () => rootRoute,
  path: "/products",
  validateSearch: z.object({
    page: z.number().default(1),
    sort: z.enum(["price", "name", "date"]).default("date"),
    category: z.string().optional(),
    minPrice: z.number().optional(),
  }),
  component: ProductsPage,
});

function ProductsPage() {
  const { page, sort, category } = productsRoute.useSearch(); // All typed!
  const navigate = productsRoute.useNavigate();

  return (
    <button onClick={() => navigate({ search: (prev) => ({ ...prev, page: prev.page + 1 }) })}>
      Next Page
    </button>
  );
}
Enter fullscreen mode Exit fullscreen mode

Pending UI + Stale-While-Revalidate

const route = createRoute({
  path: "/data",
  loader: ({ context }) => context.queryClient.ensureQueryData(dataQuery),
  pendingComponent: () => <Skeleton />,
  errorComponent: ({ error }) => <ErrorView error={error} />,
  staleTime: 30_000, // Show stale data for 30s while revalidating
});
Enter fullscreen mode Exit fullscreen mode

File-Based Routing

src/routes/
  __root.tsx           → Root layout
  index.tsx            → /
  about.tsx            → /about
  products/
    index.tsx          → /products
    $productId.tsx     → /products/:productId
    $productId.edit.tsx → /products/:productId/edit
Enter fullscreen mode Exit fullscreen mode

Devtools

import { TanStackRouterDevtools } from "@tanstack/router-devtools";

function RootLayout() {
  return (
    <>
      <Outlet />
      <TanStackRouterDevtools position="bottom-right" />
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

Building data-driven apps? My Apify tools feed structured data into your TanStack-powered routes.

Custom solution? Email spinov001@gmail.com

Top comments (0)