Lesson 1 — Folders, route files, and nesting
TanStack Router supports directory-based routing just like Next.js. A folder is a path segment, and route.tsx defines the route component. The mental model carries over — you just need to know which files do what.
In Next.js App Router:
In TanStack Router (directory-based):
route.tsx is like Next.js page.tsx + layout.tsx combined. If a folder has route.tsx, it becomes a route in the tree. Child folders in that directory become nested routes.
| File/Folder | Purpose |
|---|---|
__root.tsx | Root layout — wraps entire app |
route.tsx | Route component — defines a layout route |
index.tsx | Index route — renders at parent path (e.g., /home from home/index.tsx) |
Layout route (route.tsx): Renders children via <Outlet />
// routes/settings/route.tsx
import { Outlet, createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/settings')({
component: SettingsLayout,
})
function SettingsLayout() {
return (
<div>
<h1>Settings</h1>
<Outlet /> {/* child routes render here */}
</div>
)
}
Index route (index.tsx): Renders at the parent path, no children
// routes/settings/index.tsx
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/settings/')({
component: SettingsHome,
})
function SettingsHome() {
return <div>Choose a setting from the sidebar</div>
}
In Next.js, layouts get {children} automatically. In TanStack Router, you explicitly choose where child routes render using <Outlet />.
When you visit /settings/account:
TanStack Router renders both components, plugging the child into the outlet:
| URL | Component Tree |
|---|---|
/settings | <SettingsLayout> |
/settings/account | <SettingsLayout><AccountSettings /></SettingsLayout> |
Let's model a typical mobile social app: tabs at the bottom, detail screens, and settings.
_app/ is a pathless route. It wraps children but does not add a segment to the URL. The URL is /explore, not /_app/explore. We'll cover this fully in Lesson 2.
| URL | Rendered Tree |
|---|---|
/ | <Root><AppLayout><HomeFeed /></AppLayout></Root> |
/explore | <Root><AppLayout><Explore /></AppLayout></Root> |
/posts/42 | <Root><AppLayout><PostDetail postId="42" /></AppLayout></Root> |
/posts/42/comments | <Root><AppLayout><PostDetail postId="42"><Comments /></PostDetail></AppLayout></Root> |
Notice how /posts/42 renders <PostDetail /> inside the app layout.
But /posts/42/comments renders <Comments /> inside <PostDetail /> — which is itself inside <AppLayout />. Three levels of nesting.
routes/shop/items/$itemId/route.tsx match?$itemId is the dynamic segment. The file maps to /shop/items/:itemId.settings/route.tsx has no <Outlet />, what happens at /settings/account?<AccountSettings /> renders<SettingsLayout /> renders, but child content is lostsettings/route.tsx, but without an <Outlet /> there is nowhere to place the child. The child simply doesn't appear.route.tsx and index.tsx?route.tsx is a layout, index.tsx renders at parent pathindex.tsx wraps children, route.tsx doesn'troute.tsx creates a layout route that can have children (uses <Outlet />). index.tsx is a terminal route that renders at the parent path (e.g., /settings from settings/index.tsx)./blog/2024?blog/2024/route.tsx creates /blog/2024.__root.tsx do?/__root.tsx is the root layout — it's always rendered and wraps the entire application.posts/route.tsx and posts/index.tsx, what renders at /posts?posts/route.tsxposts/index.tsxposts/route.tsx is the layout (with <Outlet />), and posts/index.tsx content renders inside it.routes/admin/users/edit/route.tsx create?admin, users, edit — that's three segments, plus the route.tsx creates the route at /admin/users/edit.<Outlet /> in TanStack Router?<Outlet /> is where child routes render. Without it, child components won't appear in the layout.route.tsx defines the route component. A folder without route.tsx won't create a route (unless it has index.tsx and a parent with route.tsx).$postId?useParams() hookparams in loader/componentroute.params global objectuseParams() or directly in route configuration.