Skip to main content

routes.ts

Defines the route structure for your React Router application in Framework Mode. Located at app/routes.ts.

Import

import type { RouteConfig } from "@react-router/dev/routes";
import { route, index, layout, prefix } from "@react-router/dev/routes";
import { flatRoutes } from "@react-router/fs-routes";

RouteConfig Type

export interface RouteConfigEntry {
  id?: string;
  path?: string;
  index?: boolean;
  caseSensitive?: boolean;
  file: string;
  children?: RouteConfigEntry[];
}

type RouteConfig = RouteConfigEntry[];

Route Helpers

route()

Defines a route with a path and component.
path
string | null | undefined
required
URL path pattern. Use null or undefined for pathless layout routes.
  • Static: "/about"
  • Dynamic: "/users/:userId"
  • Splat: "/files/*"
file
string
required
Path to route module file, relative to app/ directory.
route("/about", "./routes/about.tsx")
children
RouteConfigEntry[]
Nested child routes.
route("/users", "./routes/users.tsx", [
  index("./routes/users.index.tsx"),
  route(":userId", "./routes/users.$userId.tsx"),
])
options
object
Additional route options:
  • id?: string - Custom route identifier
  • caseSensitive?: boolean - Case-sensitive path matching
route("/About", "./routes/about.tsx", {
  id: "about-page",
  caseSensitive: true,
})
Examples:
route("/about", "./routes/about.tsx")

index()

Defines an index route (renders at parent’s path).
file
string
required
Path to route module file.
index("./routes/home.tsx")
options
{ id?: string }
Optional custom route ID.
index("./routes/home.tsx", { id: "home" })
Examples:
route("/", "./root.tsx", [
  index("./routes/home.tsx"),
])

layout()

Defines a layout route that wraps children without adding to the URL.
file
string
required
Path to layout component file.
layout("./routes/auth-layout.tsx", [...])
children
RouteConfigEntry[]
Routes to wrap with this layout.
layout("./routes/marketing-layout.tsx", [
  route("/", "./routes/home.tsx"),
  route("/about", "./routes/about.tsx"),
])
options
{ id?: string }
Optional custom route ID.
layout("./routes/dashboard-layout.tsx", { id: "dashboard" }, [...])
Examples:
layout("./routes/marketing-layout.tsx", [
  route("/", "./routes/home.tsx"),
  route("/pricing", "./routes/pricing.tsx"),
])

prefix()

Adds a path prefix to multiple routes without a layout component.
prefixPath
string
required
Path segment to prepend to all routes.
prefix("/app", routes)
routes
RouteConfigEntry[]
required
Routes to prefix.
prefix("/admin", [
  route("/dashboard", "./routes/admin.dashboard.tsx"),
  route("/users", "./routes/admin.users.tsx"),
])
Examples:
prefix("/blog", [
  index("./routes/blog.index.tsx"),
  route(":slug", "./routes/blog.$slug.tsx"),
])
// Results in: /blog and /blog/:slug

File-System Routes

flatRoutes()

Generates routes from file-system structure using conventions.
import { flatRoutes } from "@react-router/fs-routes";

export default flatRoutes();
File Conventions:
FileRoute
routes/_index.tsx/
routes/about.tsx/about
routes/blog._index.tsx/blog
routes/blog.$slug.tsx/blog/:slug
routes/blog.$.tsx/blog/*
routes/users.$userId.tsx/users/:userId
routes/files.$.tsx/files/*
routes/_layout.tsxLayout (no path)
routes/dashboard.settings.tsx/dashboard/settings
Directory Structure Example:
app/
├── routes/
│   ├── _index.tsx           → /
│   ├── about.tsx            → /about
│   ├── blog._index.tsx      → /blog
│   ├── blog.$slug.tsx       → /blog/:slug
│   ├── users._index.tsx     → /users
│   ├── users.$userId.tsx    → /users/:userId
│   └── dashboard.settings.tsx → /dashboard/settings
├── routes.ts
└── root.tsx

Custom Base Directory

import { flatRoutes } from "@react-router/fs-routes";

export default flatRoutes({
  rootDirectory: "custom-routes",
});

Common Patterns

Mixed Approach

Combine file-system routes with manual configuration:
import { flatRoutes } from "@react-router/fs-routes";
import { route, prefix } from "@react-router/dev/routes";

export default [
  // File-system routes
  ...flatRoutes(),
  
  // Manual API routes
  prefix("/api", [
    route("/users", "./api/users.ts"),
    route("/posts", "./api/posts.ts"),
  ]),
];

Nested Route Groups

import { route, index, layout } from "@react-router/dev/routes";

export default [
  // Public routes
  layout("./layouts/public.tsx", [
    route("/", "./routes/home.tsx"),
    route("/about", "./routes/about.tsx"),
    route("/pricing", "./routes/pricing.tsx"),
  ]),
  
  // App routes (authenticated)
  layout("./layouts/app.tsx", [
    route("/dashboard", "./routes/dashboard.tsx", [
      index("./routes/dashboard.index.tsx"),
      route("settings", "./routes/dashboard.settings.tsx"),
    ]),
  ]),
  
  // Admin routes
  layout("./layouts/admin.tsx", [
    prefix("/admin", [
      route("/users", "./routes/admin.users.tsx"),
      route("/settings", "./routes/admin.settings.tsx"),
    ]),
  ]),
];

Dynamic Route Segments

import { route, index } from "@react-router/dev/routes";

export default [
  route("/users/:userId", "./routes/users.$userId.tsx"),
  route("/posts/:postId", "./routes/posts.$postId.tsx", [
    index("./routes/posts.$postId.index.tsx"),
    route("edit", "./routes/posts.$postId.edit.tsx"),
  ]),
  route("/files/*", "./routes/files.$.tsx"),
];

Relative Route Helpers

Organize routes across multiple files:
import { relative } from "@react-router/dev/routes";
import { adminRoutes } from "./routes/admin/routes";
import { blogRoutes } from "./routes/blog/routes";

export default [
  ...adminRoutes,
  ...blogRoutes,
];
import { relative } from "@react-router/dev/routes";
import { getAppDirectory } from "@react-router/dev/routes";
import path from "path";

const { route, index, layout } = relative(
  path.join(getAppDirectory(), "routes/admin")
);

export const adminRoutes = [
  layout("layout.tsx", [
    route("/admin", "dashboard.tsx"),
    route("/admin/users", "users.tsx"),
  ]),
];

Resource Routes (No UI)

import { route } from "@react-router/dev/routes";

export default [
  route("/api/webhook", "./routes/webhook.ts"),
  route("/healthcheck", "./routes/healthcheck.ts"),
  route("/sitemap.xml", "./routes/sitemap.ts"),
];

Validation

The route config is validated at build time:
// ✅ Valid
route("/users", "./routes/users.tsx")

// ❌ Invalid - missing file
route("/users", "./routes/users.tsx") // Error: File not found

// ❌ Invalid - reserved ID
route("/users", "./routes/users.tsx", { id: "root" }) // Error: Cannot use 'root' as ID

// ❌ Invalid - duplicate IDs
route("/a", "./a.tsx", { id: "same" })
route("/b", "./b.tsx", { id: "same" }) // Error: Duplicate ID

TypeScript

Ensure proper type checking:
import type { RouteConfig } from "@react-router/dev/routes";
import { route, index } from "@react-router/dev/routes";

export default [
  route("/", "./routes/home.tsx"),
  route("/about", "./routes/about.tsx"),
] satisfies RouteConfig;

Build docs developers (and LLMs) love