How OpenSEO Implements Routing with TanStack Router: Complete Guide

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 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 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.

// 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.

// 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.

// 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.

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.

// 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 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.

// 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 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 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 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 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →