# How OpenSEO Implements Routing with TanStack Router: Complete Guide

> Explore how OpenSEO implements routing with TanStack Router. Learn about file-based routing, createRoute and createRouter for authentication and layouts. Get the complete guide.

- Repository: [Every App/open-seo](https://github.com/every-app/open-seo)
- Tags: how-to-guide
- Published: 2026-08-05

---

**OpenSEO uses TanStack Router with a file-based routing system where routes are defined in `src/routes/` using `createFileRoute`, orchestrated through a central `createRouter` instance in [`src/router.tsx`](https://github.com/every-app/open-seo/blob/main/src/router.tsx) that handles authentication guards and layout wrapping.**

OpenSEO is an open-source SEO management application built by every-app that leverages TanStack Router (formerly TanStack Start) for type-safe client-side navigation. The routing architecture follows a file-based convention where URL paths automatically map to the file structure under `src/routes/`, enabling nested layouts, dynamic parameters, and automatic route tree generation without manual configuration.

## Central Router Configuration

The routing system initializes in [`src/router.tsx`](https://github.com/every-app/open-seo/blob/main/src/router.tsx) where the application creates a single router instance using `createRouter` from `@tanstack/react-router`. This file imports the auto-generated `routeTree` from `./routeTree.gen` and configures global behaviors including authentication checks and default layouts.

```tsx
// src/router.tsx – central router definition
import { createRouter as createTanStackRouter } from '@tanstack/react-router';
import { routeTree } from './routeTree.gen'; // auto‑generated from src/routes

export const router = createTanStackRouter({
  routeTree,
  defaultPreload: async ({ location, preload }) => {
    // Example auth guard
    const session = await preload('session');
    if (!session?.user && location.pathname !== '/_auth/sign-in') {
      throw router.redirect({ to: '/_auth/sign-in' });
    }
  },
  defaultComponent: ({ children }) => <Layout>{children}</Layout>,
});

```

The `defaultPreload` function runs before rendering any route, checking for an active session and redirecting unauthenticated users to the `/_auth/sign-in` page. The `defaultComponent` wraps every route with a shared layout, ensuring consistent UI elements like navigation bars appear across all pages.

## File-Based Route Definitions

OpenSEO follows TanStack Router's file-based convention where each route file under `src/routes/` exports a `Route` object created via `createFileRoute`. The file path determines the URL structure automatically.

```tsx
// src/routes/_app/index.tsx – defining a top‑level route
import { createFileRoute } from '@tanstack/react-router';
import { HomePage } from '../../client/pages/HomePage';

export const Route = createFileRoute('/')({
  component: HomePage,
});

```

Files prefixed with an underscore (e.g., `_app/`) create layout routes that group child routes without adding path segments. The `createFileRoute` function accepts the route path as its first argument and returns a configuration object where you define the component, loaders, and other route-specific options.

## Dynamic Routes and Loaders

Nested directories generate nested routes automatically, while dynamic parameters use the `$parameter` syntax in filenames. For example, `src/routes/_project/p/$projectId/keywords.tsx` becomes accessible at `/p/:projectId/keywords` and receives the project ID as a typed parameter.

```tsx
// src/routes/_project/p/$projectId/keywords.tsx – a nested, parameterized route
import { createFileRoute, redirect } from '@tanstack/react-router';
import { KeywordsPage } from '../../client/features/keywords/page/KeywordsPage';

export const Route = createFileRoute('/_project/p/$projectId/keywords')({
  loader: async ({ params }) => {
    // Redirect if the project has no keywords yet
    const hasKeywords = await checkKeywords(params.projectId);
    if (!hasKeywords) return redirect({ to: '/_project/p/$projectId' });
  },
  component: KeywordsPage,
});

```

Route loaders execute before the component renders, enabling data fetching or conditional redirects. The `redirect` utility from `@tanstack/react-router` allows programmatic navigation based on business logic, such as redirecting the guides index to the first guide entry in [`web/src/routes/guides/index.tsx`](https://github.com/every-app/open-seo/blob/main/web/src/routes/guides/index.tsx).

## Navigation and Link Components

UI navigation throughout OpenSEO uses the `<Link>` component from `@tanstack/react-router`, which enables preloading and client-side transitions without full page refreshes. This component appears in various UI elements like the site footer defined in [`web/src/components/site-footer.tsx`](https://github.com/every-app/open-seo/blob/main/web/src/components/site-footer.tsx).

```tsx
// Using the <Link> component for navigation
import { Link } from '@tanstack/react-router';

export function NavBar() {
  return (
    <nav>
      <Link to="/">Dashboard</Link>
      <Link to="/_project/p/123/keywords">Keywords</Link>
    </nav>
  );
}

```

The `<Link>` component integrates with the router's SPA navigation system, automatically handling active state styling and prefetching route data when the user hovers over links. This ensures sub-millisecond navigation between pages once the initial application bundle loads.

## Root Route and Development Tools

The root route in [`src/routes/__root.tsx`](https://github.com/every-app/open-seo/blob/main/src/routes/__root.tsx) serves as the application shell, mounting the TanStack Router Devtools for debugging route matches and state. This file exports a `Route` component that renders the outlet where child routes appear.

```tsx
// src/routes/__root.tsx
import { createRootRoute } from '@tanstack/react-router';
import { TanStackRouterDevtools } from '@tanstack/router-devtools';

export const Route = createRootRoute({
  component: () => (
    <>
      <Outlet />
      <TanStackRouterDevtools />
    </>
  ),
});

```

Attaching devtools to the root route provides a debugging interface in development environments, allowing developers to inspect the current route tree, search params, and loader data without external browser extensions.

## Summary

- **File-based routing**: Routes auto-generate from `src/routes/` using `createFileRoute`, with file paths determining URL structures.
- **Centralized configuration**: [`src/router.tsx`](https://github.com/every-app/open-seo/blob/main/src/router.tsx) creates the router instance with global authentication guards via `defaultPreload` and layout wrappers via `defaultComponent`.
- **Dynamic parameters**: Use `$parameter` syntax in filenames for type-safe dynamic segments, accessible in loaders and components.
- **SPA navigation**: The `<Link>` component handles client-side navigation with preloading capabilities.
- **Development tooling**: TanStack Router Devtools mount in [`__root.tsx`](https://github.com/every-app/open-seo/blob/main/__root.tsx) for route debugging.

## Frequently Asked Questions

### What is the difference between TanStack Start and TanStack Router in OpenSEO?

OpenSEO specifically implements **TanStack Router** as its client-side routing library. While TanStack Start refers to the full-stack framework, the every-app/open-seo repository uses TanStack Router's file-based routing system to handle navigation, layouts, and data loading within a React application.

### How does OpenSEO handle authentication and protected routes?

The router configuration in [`src/router.tsx`](https://github.com/every-app/open-seo/blob/main/src/router.tsx) defines a `defaultPreload` function that validates user sessions before rendering any route. Unauthenticated users are automatically redirected to the `/_auth/sign-in` route, ensuring all routes are protected by default unless explicitly excluded in the preload logic.

### Can routes perform redirects based on data conditions?

Yes, routes can return redirects inside their `loader` functions using the `redirect` utility from `@tanstack/react-router`. For example, the keywords route checks if a project has existing keywords and redirects to the project overview if the keywords list is empty, as implemented in `src/routes/_project/p/$projectId/keywords.tsx`.

### Where does OpenSEO define the root layout that wraps all pages?

The root layout is defined in [`src/routes/__root.tsx`](https://github.com/every-app/open-seo/blob/main/src/routes/__root.tsx) using `createRootRoute`, which renders the `<Outlet>` component where child routes appear. This file also attaches the TanStack Router Devtools for development debugging, making it the central mounting point for application-wide UI elements.