Skip to main content
Inmobiliaria Web uses TanStack Router for type-safe, file-based routing with automatic code splitting.

Overview

File-Based

Routes automatically discovered from src/routes/ directory

Type-Safe

Full TypeScript support with autocomplete

Code Splitting

Automatic route-based code splitting

Nested Layouts

Support for layout routes and nested routing

Router Configuration

Setup in src/main.tsx

The router is created and configured at the application entry point:
src/main.tsx
import { StrictMode } from "react";
import ReactDOM from "react-dom/client";
import { RouterProvider, createRouter } from "@tanstack/react-router";
import { Toaster } from "react-hot-toast";
import "./index.css";

// Import the generated route tree
import { routeTree } from "./routeTree.gen";

// Create a new router instance
const router = createRouter({
  routeTree,
  scrollRestoration: true,  // Auto-restore scroll position
});

// Register the router instance for type safety
declare module "@tanstack/react-router" {
  interface Register {
    router: typeof router;
  }
}

// Render the app
const rootElement = document.getElementById("root")!;
if (!rootElement.innerHTML) {
  const root = ReactDOM.createRoot(rootElement);
  root.render(
    <StrictMode>
      <RouterProvider router={router} />
      <Toaster position="top-right" />
    </StrictMode>
  );
}
The scrollRestoration: true option automatically restores scroll position when navigating back/forward through browser history.

File-Based Routing

Route File Naming Conventions

TanStack Router uses file names to determine route paths:
File NameRoute PathDescription
index.tsx/Index route of parent
nosotros.tsx/nosotrosStatic route
$propertyId.tsx/:propertyIdDynamic parameter
p.$slug.tsx/p/:slugSegment + dynamic param
__root.tsxN/ARoot layout
admin.tsx/adminLayout route (with children)

Route File Structure

routes/
├── __root.tsx           → Root layout (always rendered)
├── index.tsx            → / (homepage)
├── nosotros.tsx         → /nosotros
├── servicios.tsx        → /servicios
├── propiedades.tsx      → /propiedades (layout)
├── propiedades.index.tsx → /propiedades (content)
├── propiedades.$propertyId.tsx → /propiedades/:id
└── admin/
    ├── index.tsx        → /admin
    └── property/
        └── new.tsx      → /admin/property/new

Root Route

src/routes/__root.tsx

The root route defines the base layout for all pages:
src/routes/__root.tsx
import { createRootRoute, Outlet } from "@tanstack/react-router";
import { TanStackRouterDevtools } from "@tanstack/react-router-devtools";
import { AuthProvider } from "../contexts/AuthContext";
import Header from "../components/Header";
import Footer from "../components/Footer";
import WhatsAppButton from "../components/WhatsAppButton";

export const Route = createRootRoute({
  component: () => (
    <AuthProvider>
      <Header />
      <Outlet />  {/* Child routes render here */}
      <Footer />
      <WhatsAppButton />
      <TanStackRouterDevtools />
    </AuthProvider>
  ),
});
The <Outlet /> component is where child routes are rendered. This enables nested layouts.

Route Definition Examples

Simple Route

src/routes/index.tsx
import { createFileRoute } from "@tanstack/react-router";
import HomePage from "../pages/HomePage";

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

Dynamic Route with Parameters

src/routes/propiedades.$propertyId.tsx
import { createFileRoute } from "@tanstack/react-router";
import PropertyDetailPage from "../pages/PropertyDetailPage";

export const Route = createFileRoute("/propiedades/$propertyId")({
  component: PropertyDetailPage,
});

// Access params in component:
function PropertyDetailPage() {
  const { propertyId } = Route.useParams();
  // ...
}

Layout Route

Layout routes render an <Outlet /> for child routes:
src/routes/admin.tsx
import { createFileRoute, Outlet } from "@tanstack/react-router";
import SecureRoute from "../components/SecureRoute";

export const Route = createFileRoute("/admin")({
  component: () => (
    <SecureRoute requiredRole="admin">
      <div className="admin-layout">
        <aside>Admin Sidebar</aside>
        <main>
          <Outlet />  {/* Child admin routes */}
        </main>
      </div>
    </SecureRoute>
  ),
});

Protected Route

Use the SecureRoute component to protect routes:
src/routes/favorites.tsx
import { createFileRoute } from "@tanstack/react-router";
import SecureRoute from "../components/SecureRoute";
import FavoritesPage from "../pages/FavoritesPage";

export const Route = createFileRoute("/favorites")({
  component: () => (
    <SecureRoute>
      <FavoritesPage />
    </SecureRoute>
  ),
});

Route Tree Generation

Auto-Generated src/routeTree.gen.ts

The TanStack Router Vite plugin automatically generates a type-safe route tree:
src/routeTree.gen.ts
// This file is automatically generated by TanStack Router
// You should NOT make any changes in this file

import { Route as rootRouteImport } from './routes/__root'
import { Route as IndexRouteImport } from './routes/index'
import { Route as AdminRouteImport } from './routes/admin'
// ... more imports

export const routeTree = rootRouteImport
  ._addFileChildren(rootRouteChildren)
  ._addFileTypes<FileRouteTypes>()
Never edit src/routeTree.gen.ts manually. It is regenerated on every file change during development.

Vite Plugin Configuration

vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { tanstackRouter } from "@tanstack/router-plugin/vite";

export default defineConfig({
  plugins: [
    tanstackRouter({
      target: "react",
      autoCodeSplitting: true,  // Split code by route
    }),
    react(),
  ],
});
Type-safe navigation with the Link component:
import { Link } from "@tanstack/react-router";

function Navigation() {
  return (
    <nav>
      <Link to="/">Home</Link>
      <Link to="/nosotros">About</Link>
      <Link 
        to="/propiedades/$propertyId" 
        params={{ propertyId: "123" }}
      >
        Property 123
      </Link>
    </nav>
  );
}

Programmatic Navigation

Navigate programmatically using the useNavigate hook:
import { useNavigate } from "@tanstack/react-router";

function MyComponent() {
  const navigate = useNavigate();

  const handleClick = () => {
    navigate({ to: "/admin" });
  };

  const handlePropertyClick = (id: string) => {
    navigate({ 
      to: "/propiedades/$propertyId",
      params: { propertyId: id }
    });
  };

  return <button onClick={handleClick}>Go to Admin</button>;
}

Search Parameters

Handle query parameters type-safely:
import { useSearch } from "@tanstack/react-router";

// Define search params schema
type SearchParams = {
  type?: string;
  minPrice?: number;
  maxPrice?: number;
};

function ListingsPage() {
  const search = useSearch({ from: "/propiedades" });
  
  console.log(search.type);     // Type-safe access
  console.log(search.minPrice);
  
  return <div>Listings</div>;
}

// Link with search params
<Link 
  to="/propiedades" 
  search={{ type: "casa", minPrice: 100000 }}
>
  View Houses
</Link>

Route Organization

Public Routes

/                      → Homepage
/nosotros              → About page
/servicios             → Services page
/quiero-vender         → Sell property page
/propiedades           → Property listings
/propiedades/:id       → Property details
/propiedades/p/:slug   → Property details (SEO-friendly)

Authentication Routes

/auth                  → Login/Register
/auth/forgot-password  → Forgot password form
/auth/reset-password   → Reset password form
/auth/verify-email     → Email verification
/auth/verify-email-pending → Verification pending message

Protected Routes

/favorites             → User favorites (requires login)
/admin                 → Admin dashboard (requires admin role)
/admin/property/new    → Create property (requires admin)
/admin/property/edit/:id → Edit property (requires admin)

Route Params & Hooks

Access dynamic route parameters:
const { propertyId } = Route.useParams();
Programmatically navigate between routes:
const navigate = useNavigate();
navigate({ to: "/admin" });
Access and manage URL search parameters:
const search = useSearch({ from: "/propiedades" });
Get current location information:
const location = useLocation();
console.log(location.pathname);

Route Guards & Protection

SecureRoute Component

The SecureRoute component protects routes based on authentication and roles:
src/components/SecureRoute.tsx
import { useAuth } from "../contexts/AuthContext";
import { Navigate } from "@tanstack/react-router";

interface SecureRouteProps {
  children: React.ReactNode;
  requiredRole?: "admin" | "agent";
}

export default function SecureRoute({ 
  children, 
  requiredRole 
}: SecureRouteProps) {
  const { user, isLoading } = useAuth();

  if (isLoading) return <div>Loading...</div>;
  
  if (!user) {
    return <Navigate to="/auth" />;
  }

  if (requiredRole && user.role !== requiredRole) {
    return <Navigate to="/" />;
  }

  return <>{children}</>;
}

Code Splitting

TanStack Router automatically splits code by route when autoCodeSplitting: true is enabled:
vite.config.ts
tanstackRouter({
  target: "react",
  autoCodeSplitting: true,  // Each route becomes a separate chunk
}),
Benefits:
  • Smaller initial bundle size
  • Faster page loads
  • Routes loaded on demand

Developer Tools

TanStack Router Devtools

The devtools are included in development mode:
src/routes/__root.tsx
import { TanStackRouterDevtools } from "@tanstack/react-router-devtools";

export const Route = createRootRoute({
  component: () => (
    <>
      {/* Your layout */}
      <TanStackRouterDevtools />  {/* Only in dev mode */}
    </>
  ),
});
Features:
  • Visual route tree explorer
  • Active route highlighting
  • Params and search inspection
  • Navigation history
Press the TanStack Router icon in the bottom corner of your dev app to open the devtools.

Route Patterns

Index Routes

Use index.tsx for default route content
/propiedades → propiedades.index.tsx

Pathless Routes

Use layouts without changing the URL
admin.tsx → Layout for /admin/*

Dynamic Segments

Use $param for dynamic values
$propertyId.tsx → /:propertyId

Nested Routes

Use folders for route nesting
admin/property/new.tsx

Migration from React Router

If migrating from React Router, key differences:
React RouterTanStack Router
<Routes> + <Route>File-based routing
useParams()Route.useParams()
useSearchParams()useSearch()
Manual code splittingAutomatic
Runtime type checkingCompile-time type safety

Best Practices

Route files should only define the route and reference page components:
// Good
export const Route = createFileRoute("/nosotros")({
  component: AboutPage,
});

// Avoid heavy logic in route files
Extract common layouts to avoid duplication:
// admin.tsx provides layout for all /admin/* routes
export const Route = createFileRoute("/admin")({
  component: AdminLayout,
});
Define types for search parameters:
type SearchParams = {
  page?: number;
  type?: string;
};
Let the router handle code splitting automatically - don’t manually lazy load route components.

Next Steps

Tech Stack

Learn about the technologies used

Project Structure

Explore the codebase organization

Build docs developers (and LLMs) love