@depup/tanstack__react-router 1.166.4-depup.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (363) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +32 -0
  3. package/dist/cjs/Asset.cjs +177 -0
  4. package/dist/cjs/Asset.cjs.map +1 -0
  5. package/dist/cjs/Asset.d.cts +5 -0
  6. package/dist/cjs/CatchBoundary.cjs +114 -0
  7. package/dist/cjs/CatchBoundary.cjs.map +1 -0
  8. package/dist/cjs/CatchBoundary.d.cts +12 -0
  9. package/dist/cjs/ClientOnly.cjs +21 -0
  10. package/dist/cjs/ClientOnly.cjs.map +1 -0
  11. package/dist/cjs/ClientOnly.d.cts +49 -0
  12. package/dist/cjs/HeadContent.cjs +15 -0
  13. package/dist/cjs/HeadContent.cjs.map +1 -0
  14. package/dist/cjs/HeadContent.d.cts +6 -0
  15. package/dist/cjs/HeadContent.dev.cjs +41 -0
  16. package/dist/cjs/HeadContent.dev.cjs.map +1 -0
  17. package/dist/cjs/HeadContent.dev.d.cts +10 -0
  18. package/dist/cjs/Match.cjs +255 -0
  19. package/dist/cjs/Match.cjs.map +1 -0
  20. package/dist/cjs/Match.d.cts +14 -0
  21. package/dist/cjs/Matches.cjs +138 -0
  22. package/dist/cjs/Matches.cjs.map +1 -0
  23. package/dist/cjs/Matches.d.cts +68 -0
  24. package/dist/cjs/RouterProvider.cjs +32 -0
  25. package/dist/cjs/RouterProvider.cjs.map +1 -0
  26. package/dist/cjs/RouterProvider.d.cts +23 -0
  27. package/dist/cjs/SafeFragment.cjs +8 -0
  28. package/dist/cjs/SafeFragment.cjs.map +1 -0
  29. package/dist/cjs/SafeFragment.d.cts +1 -0
  30. package/dist/cjs/ScriptOnce.cjs +22 -0
  31. package/dist/cjs/ScriptOnce.cjs.map +1 -0
  32. package/dist/cjs/ScriptOnce.d.cts +6 -0
  33. package/dist/cjs/Scripts.cjs +56 -0
  34. package/dist/cjs/Scripts.cjs.map +1 -0
  35. package/dist/cjs/Scripts.d.cts +5 -0
  36. package/dist/cjs/ScrollRestoration.cjs +38 -0
  37. package/dist/cjs/ScrollRestoration.cjs.map +1 -0
  38. package/dist/cjs/ScrollRestoration.d.cts +14 -0
  39. package/dist/cjs/Transitioner.cjs +119 -0
  40. package/dist/cjs/Transitioner.cjs.map +1 -0
  41. package/dist/cjs/Transitioner.d.cts +1 -0
  42. package/dist/cjs/awaited.cjs +51 -0
  43. package/dist/cjs/awaited.cjs.map +1 -0
  44. package/dist/cjs/awaited.d.cts +14 -0
  45. package/dist/cjs/fileRoute.cjs +109 -0
  46. package/dist/cjs/fileRoute.cjs.map +1 -0
  47. package/dist/cjs/fileRoute.d.cts +87 -0
  48. package/dist/cjs/headContentUtils.cjs +185 -0
  49. package/dist/cjs/headContentUtils.cjs.map +1 -0
  50. package/dist/cjs/headContentUtils.d.cts +7 -0
  51. package/dist/cjs/history.d.cts +8 -0
  52. package/dist/cjs/index.cjs +241 -0
  53. package/dist/cjs/index.cjs.map +1 -0
  54. package/dist/cjs/index.d.cts +51 -0
  55. package/dist/cjs/index.dev.cjs +241 -0
  56. package/dist/cjs/index.dev.cjs.map +1 -0
  57. package/dist/cjs/index.dev.d.cts +2 -0
  58. package/dist/cjs/lazyRouteComponent.cjs +70 -0
  59. package/dist/cjs/lazyRouteComponent.cjs.map +1 -0
  60. package/dist/cjs/lazyRouteComponent.d.cts +11 -0
  61. package/dist/cjs/link.cjs +573 -0
  62. package/dist/cjs/link.cjs.map +1 -0
  63. package/dist/cjs/link.d.cts +98 -0
  64. package/dist/cjs/matchContext.cjs +27 -0
  65. package/dist/cjs/matchContext.cjs.map +1 -0
  66. package/dist/cjs/matchContext.d.cts +3 -0
  67. package/dist/cjs/not-found.cjs +38 -0
  68. package/dist/cjs/not-found.cjs.map +1 -0
  69. package/dist/cjs/not-found.d.cts +9 -0
  70. package/dist/cjs/renderRouteNotFound.cjs +22 -0
  71. package/dist/cjs/renderRouteNotFound.cjs.map +1 -0
  72. package/dist/cjs/renderRouteNotFound.d.cts +10 -0
  73. package/dist/cjs/route.cjs +198 -0
  74. package/dist/cjs/route.cjs.map +1 -0
  75. package/dist/cjs/route.d.cts +142 -0
  76. package/dist/cjs/router.cjs +22 -0
  77. package/dist/cjs/router.cjs.map +1 -0
  78. package/dist/cjs/router.d.cts +83 -0
  79. package/dist/cjs/routerContext.cjs +23 -0
  80. package/dist/cjs/routerContext.cjs.map +1 -0
  81. package/dist/cjs/routerContext.d.cts +3 -0
  82. package/dist/cjs/scroll-restoration.cjs +39 -0
  83. package/dist/cjs/scroll-restoration.cjs.map +1 -0
  84. package/dist/cjs/scroll-restoration.d.cts +1 -0
  85. package/dist/cjs/ssr/RouterClient.cjs +25 -0
  86. package/dist/cjs/ssr/RouterClient.cjs.map +1 -0
  87. package/dist/cjs/ssr/RouterClient.d.cts +4 -0
  88. package/dist/cjs/ssr/RouterServer.cjs +9 -0
  89. package/dist/cjs/ssr/RouterServer.cjs.map +1 -0
  90. package/dist/cjs/ssr/RouterServer.d.cts +4 -0
  91. package/dist/cjs/ssr/client.cjs +12 -0
  92. package/dist/cjs/ssr/client.cjs.map +1 -0
  93. package/dist/cjs/ssr/client.d.cts +2 -0
  94. package/dist/cjs/ssr/defaultRenderHandler.cjs +15 -0
  95. package/dist/cjs/ssr/defaultRenderHandler.cjs.map +1 -0
  96. package/dist/cjs/ssr/defaultRenderHandler.d.cts +1 -0
  97. package/dist/cjs/ssr/defaultStreamHandler.cjs +16 -0
  98. package/dist/cjs/ssr/defaultStreamHandler.cjs.map +1 -0
  99. package/dist/cjs/ssr/defaultStreamHandler.d.cts +1 -0
  100. package/dist/cjs/ssr/renderRouterToStream.cjs +73 -0
  101. package/dist/cjs/ssr/renderRouterToStream.cjs.map +1 -0
  102. package/dist/cjs/ssr/renderRouterToStream.d.cts +8 -0
  103. package/dist/cjs/ssr/renderRouterToString.cjs +31 -0
  104. package/dist/cjs/ssr/renderRouterToString.cjs.map +1 -0
  105. package/dist/cjs/ssr/renderRouterToString.d.cts +7 -0
  106. package/dist/cjs/ssr/serializer.d.cts +6 -0
  107. package/dist/cjs/ssr/server.cjs +20 -0
  108. package/dist/cjs/ssr/server.cjs.map +1 -0
  109. package/dist/cjs/ssr/server.d.cts +6 -0
  110. package/dist/cjs/structuralSharing.d.cts +8 -0
  111. package/dist/cjs/typePrimitives.d.cts +16 -0
  112. package/dist/cjs/useBlocker.cjs +171 -0
  113. package/dist/cjs/useBlocker.cjs.map +1 -0
  114. package/dist/cjs/useBlocker.d.cts +66 -0
  115. package/dist/cjs/useCanGoBack.cjs +8 -0
  116. package/dist/cjs/useCanGoBack.cjs.map +1 -0
  117. package/dist/cjs/useCanGoBack.d.cts +1 -0
  118. package/dist/cjs/useLoaderData.cjs +15 -0
  119. package/dist/cjs/useLoaderData.cjs.map +1 -0
  120. package/dist/cjs/useLoaderData.d.cts +19 -0
  121. package/dist/cjs/useLoaderDeps.cjs +14 -0
  122. package/dist/cjs/useLoaderDeps.cjs.map +1 -0
  123. package/dist/cjs/useLoaderDeps.d.cts +19 -0
  124. package/dist/cjs/useLocation.cjs +10 -0
  125. package/dist/cjs/useLocation.cjs.map +1 -0
  126. package/dist/cjs/useLocation.d.cts +18 -0
  127. package/dist/cjs/useMatch.cjs +47 -0
  128. package/dist/cjs/useMatch.cjs.map +1 -0
  129. package/dist/cjs/useMatch.d.cts +14 -0
  130. package/dist/cjs/useNavigate.cjs +49 -0
  131. package/dist/cjs/useNavigate.cjs.map +1 -0
  132. package/dist/cjs/useNavigate.d.cts +28 -0
  133. package/dist/cjs/useParams.cjs +17 -0
  134. package/dist/cjs/useParams.cjs.map +1 -0
  135. package/dist/cjs/useParams.d.cts +21 -0
  136. package/dist/cjs/useRouteContext.cjs +11 -0
  137. package/dist/cjs/useRouteContext.cjs.map +1 -0
  138. package/dist/cjs/useRouteContext.d.cts +3 -0
  139. package/dist/cjs/useRouter.cjs +32 -0
  140. package/dist/cjs/useRouter.cjs.map +1 -0
  141. package/dist/cjs/useRouter.d.cts +14 -0
  142. package/dist/cjs/useRouterState.cjs +38 -0
  143. package/dist/cjs/useRouterState.cjs.map +1 -0
  144. package/dist/cjs/useRouterState.d.cts +20 -0
  145. package/dist/cjs/useSearch.cjs +16 -0
  146. package/dist/cjs/useSearch.cjs.map +1 -0
  147. package/dist/cjs/useSearch.d.cts +21 -0
  148. package/dist/cjs/utils.cjs +62 -0
  149. package/dist/cjs/utils.cjs.map +1 -0
  150. package/dist/cjs/utils.d.cts +54 -0
  151. package/dist/esm/Asset.d.ts +5 -0
  152. package/dist/esm/Asset.js +160 -0
  153. package/dist/esm/Asset.js.map +1 -0
  154. package/dist/esm/CatchBoundary.d.ts +12 -0
  155. package/dist/esm/CatchBoundary.js +97 -0
  156. package/dist/esm/CatchBoundary.js.map +1 -0
  157. package/dist/esm/ClientOnly.d.ts +49 -0
  158. package/dist/esm/ClientOnly.js +21 -0
  159. package/dist/esm/ClientOnly.js.map +1 -0
  160. package/dist/esm/HeadContent.d.ts +6 -0
  161. package/dist/esm/HeadContent.dev.d.ts +10 -0
  162. package/dist/esm/HeadContent.dev.js +25 -0
  163. package/dist/esm/HeadContent.dev.js.map +1 -0
  164. package/dist/esm/HeadContent.js +15 -0
  165. package/dist/esm/HeadContent.js.map +1 -0
  166. package/dist/esm/Match.d.ts +14 -0
  167. package/dist/esm/Match.js +238 -0
  168. package/dist/esm/Match.js.map +1 -0
  169. package/dist/esm/Matches.d.ts +68 -0
  170. package/dist/esm/Matches.js +121 -0
  171. package/dist/esm/Matches.js.map +1 -0
  172. package/dist/esm/RouterProvider.d.ts +23 -0
  173. package/dist/esm/RouterProvider.js +32 -0
  174. package/dist/esm/RouterProvider.js.map +1 -0
  175. package/dist/esm/SafeFragment.d.ts +1 -0
  176. package/dist/esm/SafeFragment.js +8 -0
  177. package/dist/esm/SafeFragment.js.map +1 -0
  178. package/dist/esm/ScriptOnce.d.ts +6 -0
  179. package/dist/esm/ScriptOnce.js +22 -0
  180. package/dist/esm/ScriptOnce.js.map +1 -0
  181. package/dist/esm/Scripts.d.ts +5 -0
  182. package/dist/esm/Scripts.js +56 -0
  183. package/dist/esm/Scripts.js.map +1 -0
  184. package/dist/esm/ScrollRestoration.d.ts +14 -0
  185. package/dist/esm/ScrollRestoration.js +38 -0
  186. package/dist/esm/ScrollRestoration.js.map +1 -0
  187. package/dist/esm/Transitioner.d.ts +1 -0
  188. package/dist/esm/Transitioner.js +102 -0
  189. package/dist/esm/Transitioner.js.map +1 -0
  190. package/dist/esm/awaited.d.ts +14 -0
  191. package/dist/esm/awaited.js +34 -0
  192. package/dist/esm/awaited.js.map +1 -0
  193. package/dist/esm/fileRoute.d.ts +87 -0
  194. package/dist/esm/fileRoute.js +109 -0
  195. package/dist/esm/fileRoute.js.map +1 -0
  196. package/dist/esm/headContentUtils.d.ts +7 -0
  197. package/dist/esm/headContentUtils.js +168 -0
  198. package/dist/esm/headContentUtils.js.map +1 -0
  199. package/dist/esm/history.d.ts +8 -0
  200. package/dist/esm/index.d.ts +51 -0
  201. package/dist/esm/index.dev.d.ts +2 -0
  202. package/dist/esm/index.dev.js +133 -0
  203. package/dist/esm/index.dev.js.map +1 -0
  204. package/dist/esm/index.js +133 -0
  205. package/dist/esm/index.js.map +1 -0
  206. package/dist/esm/lazyRouteComponent.d.ts +11 -0
  207. package/dist/esm/lazyRouteComponent.js +53 -0
  208. package/dist/esm/lazyRouteComponent.js.map +1 -0
  209. package/dist/esm/link.d.ts +98 -0
  210. package/dist/esm/link.js +556 -0
  211. package/dist/esm/link.js.map +1 -0
  212. package/dist/esm/matchContext.d.ts +3 -0
  213. package/dist/esm/matchContext.js +10 -0
  214. package/dist/esm/matchContext.js.map +1 -0
  215. package/dist/esm/not-found.d.ts +9 -0
  216. package/dist/esm/not-found.js +38 -0
  217. package/dist/esm/not-found.js.map +1 -0
  218. package/dist/esm/renderRouteNotFound.d.ts +10 -0
  219. package/dist/esm/renderRouteNotFound.js +22 -0
  220. package/dist/esm/renderRouteNotFound.js.map +1 -0
  221. package/dist/esm/route.d.ts +142 -0
  222. package/dist/esm/route.js +198 -0
  223. package/dist/esm/route.js.map +1 -0
  224. package/dist/esm/router.d.ts +83 -0
  225. package/dist/esm/router.js +22 -0
  226. package/dist/esm/router.js.map +1 -0
  227. package/dist/esm/routerContext.d.ts +3 -0
  228. package/dist/esm/routerContext.js +6 -0
  229. package/dist/esm/routerContext.js.map +1 -0
  230. package/dist/esm/scroll-restoration.d.ts +1 -0
  231. package/dist/esm/scroll-restoration.js +39 -0
  232. package/dist/esm/scroll-restoration.js.map +1 -0
  233. package/dist/esm/ssr/RouterClient.d.ts +4 -0
  234. package/dist/esm/ssr/RouterClient.js +25 -0
  235. package/dist/esm/ssr/RouterClient.js.map +1 -0
  236. package/dist/esm/ssr/RouterServer.d.ts +4 -0
  237. package/dist/esm/ssr/RouterServer.js +9 -0
  238. package/dist/esm/ssr/RouterServer.js.map +1 -0
  239. package/dist/esm/ssr/client.d.ts +2 -0
  240. package/dist/esm/ssr/client.js +6 -0
  241. package/dist/esm/ssr/client.js.map +1 -0
  242. package/dist/esm/ssr/defaultRenderHandler.d.ts +1 -0
  243. package/dist/esm/ssr/defaultRenderHandler.js +15 -0
  244. package/dist/esm/ssr/defaultRenderHandler.js.map +1 -0
  245. package/dist/esm/ssr/defaultStreamHandler.d.ts +1 -0
  246. package/dist/esm/ssr/defaultStreamHandler.js +16 -0
  247. package/dist/esm/ssr/defaultStreamHandler.js.map +1 -0
  248. package/dist/esm/ssr/renderRouterToStream.d.ts +8 -0
  249. package/dist/esm/ssr/renderRouterToStream.js +73 -0
  250. package/dist/esm/ssr/renderRouterToStream.js.map +1 -0
  251. package/dist/esm/ssr/renderRouterToString.d.ts +7 -0
  252. package/dist/esm/ssr/renderRouterToString.js +31 -0
  253. package/dist/esm/ssr/renderRouterToString.js.map +1 -0
  254. package/dist/esm/ssr/serializer.d.ts +6 -0
  255. package/dist/esm/ssr/server.d.ts +6 -0
  256. package/dist/esm/ssr/server.js +14 -0
  257. package/dist/esm/ssr/server.js.map +1 -0
  258. package/dist/esm/structuralSharing.d.ts +8 -0
  259. package/dist/esm/typePrimitives.d.ts +16 -0
  260. package/dist/esm/useBlocker.d.ts +66 -0
  261. package/dist/esm/useBlocker.js +154 -0
  262. package/dist/esm/useBlocker.js.map +1 -0
  263. package/dist/esm/useCanGoBack.d.ts +1 -0
  264. package/dist/esm/useCanGoBack.js +8 -0
  265. package/dist/esm/useCanGoBack.js.map +1 -0
  266. package/dist/esm/useLoaderData.d.ts +19 -0
  267. package/dist/esm/useLoaderData.js +15 -0
  268. package/dist/esm/useLoaderData.js.map +1 -0
  269. package/dist/esm/useLoaderDeps.d.ts +19 -0
  270. package/dist/esm/useLoaderDeps.js +14 -0
  271. package/dist/esm/useLoaderDeps.js.map +1 -0
  272. package/dist/esm/useLocation.d.ts +18 -0
  273. package/dist/esm/useLocation.js +10 -0
  274. package/dist/esm/useLocation.js.map +1 -0
  275. package/dist/esm/useMatch.d.ts +14 -0
  276. package/dist/esm/useMatch.js +30 -0
  277. package/dist/esm/useMatch.js.map +1 -0
  278. package/dist/esm/useNavigate.d.ts +28 -0
  279. package/dist/esm/useNavigate.js +32 -0
  280. package/dist/esm/useNavigate.js.map +1 -0
  281. package/dist/esm/useParams.d.ts +21 -0
  282. package/dist/esm/useParams.js +17 -0
  283. package/dist/esm/useParams.js.map +1 -0
  284. package/dist/esm/useRouteContext.d.ts +3 -0
  285. package/dist/esm/useRouteContext.js +11 -0
  286. package/dist/esm/useRouteContext.js.map +1 -0
  287. package/dist/esm/useRouter.d.ts +14 -0
  288. package/dist/esm/useRouter.js +15 -0
  289. package/dist/esm/useRouter.js.map +1 -0
  290. package/dist/esm/useRouterState.d.ts +20 -0
  291. package/dist/esm/useRouterState.js +38 -0
  292. package/dist/esm/useRouterState.js.map +1 -0
  293. package/dist/esm/useSearch.d.ts +21 -0
  294. package/dist/esm/useSearch.js +16 -0
  295. package/dist/esm/useSearch.js.map +1 -0
  296. package/dist/esm/utils.d.ts +54 -0
  297. package/dist/esm/utils.js +45 -0
  298. package/dist/esm/utils.js.map +1 -0
  299. package/dist/llms/index.d.ts +3 -0
  300. package/dist/llms/index.js +43 -0
  301. package/dist/llms/rules/api.d.ts +2 -0
  302. package/dist/llms/rules/api.js +4612 -0
  303. package/dist/llms/rules/guide.d.ts +2 -0
  304. package/dist/llms/rules/guide.js +10690 -0
  305. package/dist/llms/rules/installation.d.ts +2 -0
  306. package/dist/llms/rules/installation.js +1285 -0
  307. package/dist/llms/rules/routing.d.ts +2 -0
  308. package/dist/llms/rules/routing.js +1984 -0
  309. package/dist/llms/rules/setup-and-architecture.d.ts +2 -0
  310. package/dist/llms/rules/setup-and-architecture.js +920 -0
  311. package/package.json +142 -0
  312. package/src/Asset.tsx +219 -0
  313. package/src/CatchBoundary.tsx +120 -0
  314. package/src/ClientOnly.tsx +68 -0
  315. package/src/HeadContent.dev.tsx +46 -0
  316. package/src/HeadContent.tsx +22 -0
  317. package/src/Match.tsx +360 -0
  318. package/src/Matches.tsx +313 -0
  319. package/src/RouterProvider.tsx +92 -0
  320. package/src/SafeFragment.tsx +5 -0
  321. package/src/ScriptOnce.tsx +21 -0
  322. package/src/Scripts.tsx +80 -0
  323. package/src/ScrollRestoration.tsx +69 -0
  324. package/src/Transitioner.tsx +134 -0
  325. package/src/awaited.tsx +55 -0
  326. package/src/fileRoute.ts +313 -0
  327. package/src/headContentUtils.tsx +217 -0
  328. package/src/history.ts +9 -0
  329. package/src/index.dev.tsx +6 -0
  330. package/src/index.tsx +341 -0
  331. package/src/lazyRouteComponent.tsx +96 -0
  332. package/src/link.tsx +984 -0
  333. package/src/matchContext.tsx +8 -0
  334. package/src/not-found.tsx +43 -0
  335. package/src/renderRouteNotFound.tsx +35 -0
  336. package/src/route.tsx +740 -0
  337. package/src/router.ts +127 -0
  338. package/src/routerContext.tsx +4 -0
  339. package/src/scroll-restoration.tsx +45 -0
  340. package/src/ssr/RouterClient.tsx +22 -0
  341. package/src/ssr/RouterServer.tsx +9 -0
  342. package/src/ssr/client.ts +2 -0
  343. package/src/ssr/defaultRenderHandler.tsx +12 -0
  344. package/src/ssr/defaultStreamHandler.tsx +13 -0
  345. package/src/ssr/renderRouterToStream.tsx +90 -0
  346. package/src/ssr/renderRouterToString.tsx +36 -0
  347. package/src/ssr/serializer.ts +7 -0
  348. package/src/ssr/server.ts +6 -0
  349. package/src/structuralSharing.ts +47 -0
  350. package/src/typePrimitives.ts +84 -0
  351. package/src/useBlocker.tsx +320 -0
  352. package/src/useCanGoBack.ts +5 -0
  353. package/src/useLoaderData.tsx +91 -0
  354. package/src/useLoaderDeps.tsx +69 -0
  355. package/src/useLocation.tsx +52 -0
  356. package/src/useMatch.tsx +123 -0
  357. package/src/useNavigate.tsx +78 -0
  358. package/src/useParams.tsx +107 -0
  359. package/src/useRouteContext.ts +30 -0
  360. package/src/useRouter.tsx +25 -0
  361. package/src/useRouterState.tsx +86 -0
  362. package/src/useSearch.tsx +105 -0
  363. package/src/utils.ts +125 -0
@@ -0,0 +1,1984 @@
1
+ export default `# Code-Based Routing
2
+
3
+ > [!TIP]
4
+ > Code-based routing is not recommended for most applications. It is recommended to use [File-Based Routing](./file-based-routing.md) instead.
5
+
6
+ ## ⚠️ Before You Start
7
+
8
+ - If you're using [File-Based Routing](./file-based-routing.md), **skip this guide**.
9
+ - If you still insist on using code-based routing, you must read the [Routing Concepts](./routing-concepts.md) guide first, as it also covers core concepts of the router.
10
+
11
+ ## Route Trees
12
+
13
+ Code-based routing is no different from file-based routing in that it uses the same route tree concept to organize, match and compose matching routes into a component tree. The only difference is that instead of using the filesystem to organize your routes, you use code.
14
+
15
+ Let's consider the same route tree from the [Route Trees & Nesting](./route-trees.md#route-trees) guide, and convert it to code-based routing:
16
+
17
+ Here is the file-based version:
18
+
19
+ \`\`\`
20
+ routes/
21
+ ├── __root.tsx
22
+ ├── index.tsx
23
+ ├── about.tsx
24
+ ├── posts/
25
+ │ ├── index.tsx
26
+ │ ├── $postId.tsx
27
+ ├── posts.$postId.edit.tsx
28
+ ├── settings/
29
+ │ ├── profile.tsx
30
+ │ ├── notifications.tsx
31
+ ├── _pathlessLayout.tsx
32
+ ├── _pathlessLayout/
33
+ │ ├── route-a.tsx
34
+ ├── ├── route-b.tsx
35
+ ├── files/
36
+ │ ├── $.tsx
37
+ \`\`\`
38
+
39
+ And here is a summarized code-based version:
40
+
41
+ <!-- ::start:framework -->
42
+
43
+ # React
44
+
45
+ \`\`\`tsx
46
+ import { createRootRoute, createRoute } from '@tanstack/react-router'
47
+
48
+ const rootRoute = createRootRoute()
49
+
50
+ const indexRoute = createRoute({
51
+ getParentRoute: () => rootRoute,
52
+ path: '/',
53
+ })
54
+
55
+ const aboutRoute = createRoute({
56
+ getParentRoute: () => rootRoute,
57
+ path: 'about',
58
+ })
59
+
60
+ const postsRoute = createRoute({
61
+ getParentRoute: () => rootRoute,
62
+ path: 'posts',
63
+ })
64
+
65
+ const postsIndexRoute = createRoute({
66
+ getParentRoute: () => postsRoute,
67
+ path: '/',
68
+ })
69
+
70
+ const postRoute = createRoute({
71
+ getParentRoute: () => postsRoute,
72
+ path: '$postId',
73
+ })
74
+
75
+ const postEditorRoute = createRoute({
76
+ getParentRoute: () => rootRoute,
77
+ path: 'posts/$postId/edit',
78
+ })
79
+
80
+ const settingsRoute = createRoute({
81
+ getParentRoute: () => rootRoute,
82
+ path: 'settings',
83
+ })
84
+
85
+ const profileRoute = createRoute({
86
+ getParentRoute: () => settingsRoute,
87
+ path: 'profile',
88
+ })
89
+
90
+ const notificationsRoute = createRoute({
91
+ getParentRoute: () => settingsRoute,
92
+ path: 'notifications',
93
+ })
94
+
95
+ const pathlessLayoutRoute = createRoute({
96
+ getParentRoute: () => rootRoute,
97
+ id: 'pathlessLayout',
98
+ })
99
+
100
+ const pathlessLayoutARoute = createRoute({
101
+ getParentRoute: () => pathlessLayoutRoute,
102
+ path: 'route-a',
103
+ })
104
+
105
+ const pathlessLayoutBRoute = createRoute({
106
+ getParentRoute: () => pathlessLayoutRoute,
107
+ path: 'route-b',
108
+ })
109
+
110
+ const filesRoute = createRoute({
111
+ getParentRoute: () => rootRoute,
112
+ path: 'files/$',
113
+ })
114
+ \`\`\`
115
+
116
+ # Solid
117
+
118
+ \`\`\`tsx
119
+ import { createRootRoute, createRoute } from '@tanstack/solid-router'
120
+
121
+ const rootRoute = createRootRoute()
122
+
123
+ const indexRoute = createRoute({
124
+ getParentRoute: () => rootRoute,
125
+ path: '/',
126
+ })
127
+
128
+ const aboutRoute = createRoute({
129
+ getParentRoute: () => rootRoute,
130
+ path: 'about',
131
+ })
132
+
133
+ const postsRoute = createRoute({
134
+ getParentRoute: () => rootRoute,
135
+ path: 'posts',
136
+ })
137
+
138
+ const postsIndexRoute = createRoute({
139
+ getParentRoute: () => postsRoute,
140
+ path: '/',
141
+ })
142
+
143
+ const postRoute = createRoute({
144
+ getParentRoute: () => postsRoute,
145
+ path: '$postId',
146
+ })
147
+
148
+ const postEditorRoute = createRoute({
149
+ getParentRoute: () => rootRoute,
150
+ path: 'posts/$postId/edit',
151
+ })
152
+
153
+ const settingsRoute = createRoute({
154
+ getParentRoute: () => rootRoute,
155
+ path: 'settings',
156
+ })
157
+
158
+ const profileRoute = createRoute({
159
+ getParentRoute: () => settingsRoute,
160
+ path: 'profile',
161
+ })
162
+
163
+ const notificationsRoute = createRoute({
164
+ getParentRoute: () => settingsRoute,
165
+ path: 'notifications',
166
+ })
167
+
168
+ const pathlessLayoutRoute = createRoute({
169
+ getParentRoute: () => rootRoute,
170
+ id: 'pathlessLayout',
171
+ })
172
+
173
+ const pathlessLayoutARoute = createRoute({
174
+ getParentRoute: () => pathlessLayoutRoute,
175
+ path: 'route-a',
176
+ })
177
+
178
+ const pathlessLayoutBRoute = createRoute({
179
+ getParentRoute: () => pathlessLayoutRoute,
180
+ path: 'route-b',
181
+ })
182
+
183
+ const filesRoute = createRoute({
184
+ getParentRoute: () => rootRoute,
185
+ path: 'files/$',
186
+ })
187
+ \`\`\`
188
+
189
+ <!-- ::end:framework -->
190
+
191
+ ## Anatomy of a Route
192
+
193
+ All other routes other than the root route are configured using the \`createRoute\` function:
194
+
195
+ \`\`\`tsx
196
+ const route = createRoute({
197
+ getParentRoute: () => rootRoute,
198
+ path: '/posts',
199
+ component: PostsComponent,
200
+ })
201
+ \`\`\`
202
+
203
+ The \`getParentRoute\` option is a function that returns the parent route of the route you're creating.
204
+
205
+ **❓❓❓ "Wait, you're making me pass the parent route for every route I make?"**
206
+
207
+ Absolutely! The reason for passing the parent route has **everything to do with the magical type safety** of TanStack Router. Without the parent route, TypeScript would have no idea what types to supply your route with!
208
+
209
+ > [!IMPORTANT]
210
+ > For every route that's **NOT** the **Root Route** or a **Pathless Layout Route**, a \`path\` option is required. This is the path that will be matched against the URL pathname to determine if the route is a match.
211
+
212
+ When configuring route \`path\` option on a route, it ignores leading and trailing slashes (this does not include "index" route paths \`/\`). You can include them if you want, but they will be normalized internally by TanStack Router. Here is a table of valid paths and what they will be normalized to:
213
+
214
+ | Path | Normalized Path |
215
+ | -------- | --------------- |
216
+ | \`/\` | \`/\` |
217
+ | \`/about\` | \`about\` |
218
+ | \`about/\` | \`about\` |
219
+ | \`about\` | \`about\` |
220
+ | \`$\` | \`$\` |
221
+ | \`/$\` | \`$\` |
222
+ | \`/$/\` | \`$\` |
223
+
224
+ ## Manually building the route tree
225
+
226
+ When building a route tree in code, it's not enough to define the parent route of each route. You must also construct the final route tree by adding each route to its parent route's \`children\` array. This is because the route tree is not built automatically for you like it is in file-based routing.
227
+
228
+ \`\`\`tsx
229
+ /* prettier-ignore */
230
+ const routeTree = rootRoute.addChildren([
231
+ indexRoute,
232
+ aboutRoute,
233
+ postsRoute.addChildren([
234
+ postsIndexRoute,
235
+ postRoute,
236
+ ]),
237
+ postEditorRoute,
238
+ settingsRoute.addChildren([
239
+ profileRoute,
240
+ notificationsRoute,
241
+ ]),
242
+ pathlessLayoutRoute.addChildren([
243
+ pathlessLayoutARoute,
244
+ pathlessLayoutBRoute,
245
+ ]),
246
+ filesRoute.addChildren([
247
+ fileRoute,
248
+ ]),
249
+ ])
250
+ /* prettier-ignore-end */
251
+ \`\`\`
252
+
253
+ But before you can go ahead and build the route tree, you need to understand how the Routing Concepts for Code-Based Routing work.
254
+
255
+ ## Routing Concepts for Code-Based Routing
256
+
257
+ Believe it or not, file-based routing is really a superset of code-based routing and uses the filesystem and a bit of code-generation abstraction on top of it to generate this structure you see above automatically.
258
+
259
+ We're going to assume you've read the [Routing Concepts](./routing-concepts.md) guide and are familiar with each of these main concepts:
260
+
261
+ - The Root Route
262
+ - Basic Routes
263
+ - Index Routes
264
+ - Dynamic Route Segments
265
+ - Splat / Catch-All Routes
266
+ - Layout Routes
267
+ - Pathless Routes
268
+ - Non-Nested Routes
269
+
270
+ Now, let's take a look at how to create each of these route types in code.
271
+
272
+ ## The Root Route
273
+
274
+ Creating a root route in code-based routing is thankfully the same as doing so in file-based routing. Call the \`createRootRoute()\` function.
275
+
276
+ Unlike file-based routing however, you do not need to export the root route if you don't want to. It's certainly not recommended to build an entire route tree and application in a single file (although you can and we do this in the examples to demonstrate routing concepts in brevity).
277
+
278
+ <!-- ::start:framework -->
279
+
280
+ # React
281
+
282
+ \`\`\`tsx
283
+ // Standard root route
284
+ import { createRootRoute } from '@tanstack/react-router'
285
+
286
+ const rootRoute = createRootRoute()
287
+
288
+ // Root route with Context
289
+ import { createRootRouteWithContext } from '@tanstack/react-router'
290
+ import type { QueryClient } from '@tanstack/react-query'
291
+
292
+ export interface MyRouterContext {
293
+ queryClient: QueryClient
294
+ }
295
+ const rootRoute = createRootRouteWithContext<MyRouterContext>()
296
+ \`\`\`
297
+
298
+ # Solid
299
+
300
+ \`\`\`tsx
301
+ // Standard root route
302
+ import { createRootRoute } from '@tanstack/solid-router'
303
+
304
+ const rootRoute = createRootRoute()
305
+
306
+ // Root route with Context
307
+ import { createRootRouteWithContext } from '@tanstack/solid-router'
308
+ import type { QueryClient } from '@tanstack/solid-query'
309
+
310
+ export interface MyRouterContext {
311
+ queryClient: QueryClient
312
+ }
313
+ const rootRoute = createRootRouteWithContext<MyRouterContext>()
314
+ \`\`\`
315
+
316
+ <!-- ::end:framework -->
317
+
318
+ To learn more about Context in TanStack Router, see the [Router Context](../guide/router-context.md) guide.
319
+
320
+ ## Basic Routes
321
+
322
+ To create a basic route, simply provide a normal \`path\` string to the \`createRoute\` function:
323
+
324
+ \`\`\`tsx
325
+ const aboutRoute = createRoute({
326
+ getParentRoute: () => rootRoute,
327
+ path: 'about',
328
+ })
329
+ \`\`\`
330
+
331
+ See, it's that simple! The \`aboutRoute\` will match the URL \`/about\`.
332
+
333
+ ## Index Routes
334
+
335
+ Unlike file-based routing, which uses the \`index\` filename to denote an index route, code-based routing uses a single slash \`/\` to denote an index route. For example, the \`posts.index.tsx\` file from our example route tree above would be represented in code-based routing like this:
336
+
337
+ \`\`\`tsx
338
+ const postsRoute = createRoute({
339
+ getParentRoute: () => rootRoute,
340
+ path: 'posts',
341
+ })
342
+
343
+ const postsIndexRoute = createRoute({
344
+ getParentRoute: () => postsRoute,
345
+ // Notice the single slash \`/\` here
346
+ path: '/',
347
+ })
348
+ \`\`\`
349
+
350
+ So, the \`postsIndexRoute\` will match the URL \`/posts/\` (or \`/posts\`).
351
+
352
+ ## Dynamic Route Segments
353
+
354
+ Dynamic route segments work exactly the same in code-based routing as they do in file-based routing. Simply prefix a segment of the path with a \`$\` and it will be captured into the \`params\` object of the route's \`loader\` or \`component\`:
355
+
356
+ \`\`\`tsx
357
+ const postIdRoute = createRoute({
358
+ getParentRoute: () => postsRoute,
359
+ path: '$postId',
360
+ // In a loader
361
+ loader: ({ params }) => fetchPost(params.postId),
362
+ // Or in a component
363
+ component: PostComponent,
364
+ })
365
+
366
+ function PostComponent() {
367
+ const { postId } = postIdRoute.useParams()
368
+ return <div>Post ID: {postId}</div>
369
+ }
370
+ \`\`\`
371
+
372
+ > [!TIP]
373
+ > If your component is code-split, you can use the [getRouteApi function](../guide/code-splitting.md#manually-accessing-route-apis-in-other-files-with-the-getrouteapi-helper) to avoid having to import the \`postIdRoute\` configuration to get access to the typed \`useParams()\` hook.
374
+
375
+ ## Splat / Catch-All Routes
376
+
377
+ As expected, splat/catch-all routes also work the same in code-based routing as they do in file-based routing. Simply prefix a segment of the path with a \`$\` and it will be captured into the \`params\` object under the \`_splat\` key:
378
+
379
+ \`\`\`tsx
380
+ const filesRoute = createRoute({
381
+ getParentRoute: () => rootRoute,
382
+ path: 'files',
383
+ })
384
+
385
+ const fileRoute = createRoute({
386
+ getParentRoute: () => filesRoute,
387
+ path: '$',
388
+ })
389
+ \`\`\`
390
+
391
+ For the URL \`/documents/hello-world\`, the \`params\` object will look like this:
392
+
393
+ \`\`\`js
394
+ {
395
+ '_splat': 'documents/hello-world'
396
+ }
397
+ \`\`\`
398
+
399
+ ## Layout Routes
400
+
401
+ Layout routes are routes that wrap their children in a layout component. In code-based routing, you can create a layout route by simply nesting a route under another route:
402
+
403
+ \`\`\`tsx
404
+ const postsRoute = createRoute({
405
+ getParentRoute: () => rootRoute,
406
+ path: 'posts',
407
+ component: PostsLayoutComponent, // The layout component
408
+ })
409
+
410
+ function PostsLayoutComponent() {
411
+ return (
412
+ <div>
413
+ <h1>Posts</h1>
414
+ <Outlet />
415
+ </div>
416
+ )
417
+ }
418
+
419
+ const postsIndexRoute = createRoute({
420
+ getParentRoute: () => postsRoute,
421
+ path: '/',
422
+ })
423
+
424
+ const postsCreateRoute = createRoute({
425
+ getParentRoute: () => postsRoute,
426
+ path: 'create',
427
+ })
428
+
429
+ const routeTree = rootRoute.addChildren([
430
+ // The postsRoute is the layout route
431
+ // Its children will be nested under the PostsLayoutComponent
432
+ postsRoute.addChildren([postsIndexRoute, postsCreateRoute]),
433
+ ])
434
+ \`\`\`
435
+
436
+ Now, both the \`postsIndexRoute\` and \`postsCreateRoute\` will render their contents inside of the \`PostsLayoutComponent\`:
437
+
438
+ \`\`\`tsx
439
+ // URL: /posts
440
+ <PostsLayoutComponent>
441
+ <PostsIndexComponent />
442
+ </PostsLayoutComponent>
443
+
444
+ // URL: /posts/create
445
+ <PostsLayoutComponent>
446
+ <PostsCreateComponent />
447
+ </PostsLayoutComponent>
448
+ \`\`\`
449
+
450
+ ## Pathless Layout Routes
451
+
452
+ In file-based routing a pathless layout route is prefixed with a \`_\`, but in code-based routing, this is simply a route with an \`id\` instead of a \`path\` option. This is because code-based routing does not use the filesystem to organize routes, so there is no need to prefix a route with a \`_\` to denote that it has no path.
453
+
454
+ \`\`\`tsx
455
+ const pathlessLayoutRoute = createRoute({
456
+ getParentRoute: () => rootRoute,
457
+ id: 'pathlessLayout',
458
+ component: PathlessLayoutComponent,
459
+ })
460
+
461
+ function PathlessLayoutComponent() {
462
+ return (
463
+ <div>
464
+ <h1>Pathless Layout</h1>
465
+ <Outlet />
466
+ </div>
467
+ )
468
+ }
469
+
470
+ const pathlessLayoutARoute = createRoute({
471
+ getParentRoute: () => pathlessLayoutRoute,
472
+ path: 'route-a',
473
+ })
474
+
475
+ const pathlessLayoutBRoute = createRoute({
476
+ getParentRoute: () => pathlessLayoutRoute,
477
+ path: 'route-b',
478
+ })
479
+
480
+ const routeTree = rootRoute.addChildren([
481
+ // The pathless layout route has no path, only an id
482
+ // So its children will be nested under the pathless layout route
483
+ pathlessLayoutRoute.addChildren([pathlessLayoutARoute, pathlessLayoutBRoute]),
484
+ ])
485
+ \`\`\`
486
+
487
+ Now both \`/route-a\` and \`/route-b\` will render their contents inside of the \`PathlessLayoutComponent\`:
488
+
489
+ \`\`\`tsx
490
+ // URL: /route-a
491
+ <PathlessLayoutComponent>
492
+ <RouteAComponent />
493
+ </PathlessLayoutComponent>
494
+
495
+ // URL: /route-b
496
+ <PathlessLayoutComponent>
497
+ <RouteBComponent />
498
+ </PathlessLayoutComponent>
499
+ \`\`\`
500
+
501
+ ## Non-Nested Routes
502
+
503
+ Building non-nested routes in code-based routing does not require using a trailing \`_\` in the path, but does require you to build your route and route tree with the right paths and nesting. Let's consider the route tree where we want the post editor to **not** be nested under the posts route:
504
+
505
+ - \`/posts_/$postId/edit\`
506
+ - \`/posts\`
507
+ - \`$postId\`
508
+
509
+ To do this we need to build a separate route for the post editor and include the entire path in the \`path\` option from the root of where we want the route to be nested (in this case, the root):
510
+
511
+ \`\`\`tsx
512
+ // The posts editor route is nested under the root route
513
+ const postEditorRoute = createRoute({
514
+ getParentRoute: () => rootRoute,
515
+ // The path includes the entire path we need to match
516
+ path: 'posts/$postId/edit',
517
+ })
518
+
519
+ const postsRoute = createRoute({
520
+ getParentRoute: () => rootRoute,
521
+ path: 'posts',
522
+ })
523
+
524
+ const postRoute = createRoute({
525
+ getParentRoute: () => postsRoute,
526
+ path: '$postId',
527
+ })
528
+
529
+ const routeTree = rootRoute.addChildren([
530
+ // The post editor route is nested under the root route
531
+ postEditorRoute,
532
+ postsRoute.addChildren([postRoute]),
533
+ ])
534
+ \`\`\`
535
+
536
+ # File-Based Routing
537
+
538
+ Most of the TanStack Router documentation is written for file-based routing and is intended to help you understand in more detail how to configure file-based routing and the technical details behind how it works. While file-based routing is the preferred and recommended way to configure TanStack Router, you can also use [code-based routing](./code-based-routing.md) if you prefer.
539
+
540
+ ## What is File-Based Routing?
541
+
542
+ File-based routing is a way to configure your routes using the filesystem. Instead of defining your route structure via code, you can define your routes using a series of files and directories that represent the route hierarchy of your application. This brings a number of benefits:
543
+
544
+ - **Simplicity**: File-based routing is visually intuitive and easy to understand for both new and experienced developers.
545
+ - **Organization**: Routes are organized in a way that mirrors the URL structure of your application.
546
+ - **Scalability**: As your application grows, file-based routing makes it easy to add new routes and maintain existing ones.
547
+ - **Code-Splitting**: File-based routing allows TanStack Router to automatically code-split your routes for better performance.
548
+ - **Type-Safety**: File-based routing raises the ceiling on type-safety by generating managing type linkages for your routes, which can otherwise be a tedious process via code-based routing.
549
+ - **Consistency**: File-based routing enforces a consistent structure for your routes, making it easier to maintain and update your application and move from one project to another.
550
+
551
+ ## \`/\`s or \`.\`s?
552
+
553
+ While directories have long been used to represent route hierarchy, file-based routing introduces an additional concept of using the \`.\` character in the file-name to denote a route nesting. This allows you to avoid creating directories for few deeply nested routes and continue to use directories for wider route hierarchies. Let's take a look at some examples!
554
+
555
+ ## Directory Routes
556
+
557
+ Directories can be used to denote route hierarchy, which can be useful for organizing multiple routes into logical groups and also cutting down on the filename length for large groups of deeply nested routes.
558
+
559
+ See the example below:
560
+
561
+ | Filename | Route Path | Component Output |
562
+ | ----------------------- | ------------------------- | --------------------------------- |
563
+ | ʦ \`__root.tsx\` | | \`<Root>\` |
564
+ | ʦ \`index.tsx\` | \`/\` (exact) | \`<Root><RootIndex>\` |
565
+ | ʦ \`about.tsx\` | \`/about\` | \`<Root><About>\` |
566
+ | ʦ \`posts.tsx\` | \`/posts\` | \`<Root><Posts>\` |
567
+ | 📂 \`posts\` | | |
568
+ | ┄ ʦ \`index.tsx\` | \`/posts\` (exact) | \`<Root><Posts><PostsIndex>\` |
569
+ | ┄ ʦ \`$postId.tsx\` | \`/posts/$postId\` | \`<Root><Posts><Post>\` |
570
+ | 📂 \`posts_\` | | |
571
+ | ┄ 📂 \`$postId\` | | |
572
+ | ┄ ┄ ʦ \`edit.tsx\` | \`/posts/$postId/edit\` | \`<Root><EditPost>\` |
573
+ | ʦ \`settings.tsx\` | \`/settings\` | \`<Root><Settings>\` |
574
+ | 📂 \`settings\` | | \`<Root><Settings>\` |
575
+ | ┄ ʦ \`profile.tsx\` | \`/settings/profile\` | \`<Root><Settings><Profile>\` |
576
+ | ┄ ʦ \`notifications.tsx\` | \`/settings/notifications\` | \`<Root><Settings><Notifications>\` |
577
+ | ʦ \`_pathlessLayout.tsx\` | | \`<Root><PathlessLayout>\` |
578
+ | 📂 \`_pathlessLayout\` | | |
579
+ | ┄ ʦ \`route-a.tsx\` | \`/route-a\` | \`<Root><PathlessLayout><RouteA>\` |
580
+ | ┄ ʦ \`route-b.tsx\` | \`/route-b\` | \`<Root><PathlessLayout><RouteB>\` |
581
+ | 📂 \`files\` | | |
582
+ | ┄ ʦ \`$.tsx\` | \`/files/$\` | \`<Root><Files>\` |
583
+ | 📂 \`account\` | | |
584
+ | ┄ ʦ \`route.tsx\` | \`/account\` | \`<Root><Account>\` |
585
+ | ┄ ʦ \`overview.tsx\` | \`/account/overview\` | \`<Root><Account><Overview>\` |
586
+
587
+ ## Flat Routes
588
+
589
+ Flat routing gives you the ability to use \`.\`s to denote route nesting levels.
590
+
591
+ This can be useful when you have a large number of uniquely deeply nested routes and want to avoid creating directories for each one:
592
+
593
+ See the example below:
594
+
595
+ | Filename | Route Path | Component Output |
596
+ | ------------------------------- | ------------------------- | --------------------------------- |
597
+ | ʦ \`__root.tsx\` | | \`<Root>\` |
598
+ | ʦ \`index.tsx\` | \`/\` (exact) | \`<Root><RootIndex>\` |
599
+ | ʦ \`about.tsx\` | \`/about\` | \`<Root><About>\` |
600
+ | ʦ \`posts.tsx\` | \`/posts\` | \`<Root><Posts>\` |
601
+ | ʦ \`posts.index.tsx\` | \`/posts\` (exact) | \`<Root><Posts><PostsIndex>\` |
602
+ | ʦ \`posts.$postId.tsx\` | \`/posts/$postId\` | \`<Root><Posts><Post>\` |
603
+ | ʦ \`posts_.$postId.edit.tsx\` | \`/posts/$postId/edit\` | \`<Root><EditPost>\` |
604
+ | ʦ \`settings.tsx\` | \`/settings\` | \`<Root><Settings>\` |
605
+ | ʦ \`settings.profile.tsx\` | \`/settings/profile\` | \`<Root><Settings><Profile>\` |
606
+ | ʦ \`settings.notifications.tsx\` | \`/settings/notifications\` | \`<Root><Settings><Notifications>\` |
607
+ | ʦ \`_pathlessLayout.tsx\` | | \`<Root><PathlessLayout>\` |
608
+ | ʦ \`_pathlessLayout.route-a.tsx\` | \`/route-a\` | \`<Root><PathlessLayout><RouteA>\` |
609
+ | ʦ \`_pathlessLayout.route-b.tsx\` | \`/route-b\` | \`<Root><PathlessLayout><RouteB>\` |
610
+ | ʦ \`files.$.tsx\` | \`/files/$\` | \`<Root><Files>\` |
611
+ | ʦ \`account.tsx\` | \`/account\` | \`<Root><Account>\` |
612
+ | ʦ \`account.overview.tsx\` | \`/account/overview\` | \`<Root><Account><Overview>\` |
613
+
614
+ ## Mixed Flat and Directory Routes
615
+
616
+ It's extremely likely that a 100% directory or flat route structure won't be the best fit for your project, which is why TanStack Router allows you to mix both flat and directory routes together to create a route tree that uses the best of both worlds where it makes sense:
617
+
618
+ See the example below:
619
+
620
+ | Filename | Route Path | Component Output |
621
+ | ------------------------------ | ------------------------- | --------------------------------- |
622
+ | ʦ \`__root.tsx\` | | \`<Root>\` |
623
+ | ʦ \`index.tsx\` | \`/\` (exact) | \`<Root><RootIndex>\` |
624
+ | ʦ \`about.tsx\` | \`/about\` | \`<Root><About>\` |
625
+ | ʦ \`posts.tsx\` | \`/posts\` | \`<Root><Posts>\` |
626
+ | 📂 \`posts\` | | |
627
+ | ┄ ʦ \`index.tsx\` | \`/posts\` (exact) | \`<Root><Posts><PostsIndex>\` |
628
+ | ┄ ʦ \`$postId.tsx\` | \`/posts/$postId\` | \`<Root><Posts><Post>\` |
629
+ | ┄ ʦ \`$postId.edit.tsx\` | \`/posts/$postId/edit\` | \`<Root><Posts><Post><EditPost>\` |
630
+ | ʦ \`settings.tsx\` | \`/settings\` | \`<Root><Settings>\` |
631
+ | ʦ \`settings.profile.tsx\` | \`/settings/profile\` | \`<Root><Settings><Profile>\` |
632
+ | ʦ \`settings.notifications.tsx\` | \`/settings/notifications\` | \`<Root><Settings><Notifications>\` |
633
+ | ʦ \`account.tsx\` | \`/account\` | \`<Root><Account>\` |
634
+ | ʦ \`account.overview.tsx\` | \`/account/overview\` | \`<Root><Account><Overview>\` |
635
+
636
+ Both flat and directory routes can be mixed together to create a route tree that uses the best of both worlds where it makes sense.
637
+
638
+ > [!TIP]
639
+ > If you find that the default file-based routing structure doesn't fit your needs, you can always use [Virtual File Routes](./virtual-file-routes.md) to control the source of your routes whilst still getting the awesome performance benefits of file-based routing.
640
+
641
+ ## Getting started with File-Based Routing
642
+
643
+ To get started with file-based routing, you'll need to configure your project's bundler to use the TanStack Router Plugin or the TanStack Router CLI.
644
+
645
+ To enable file-based routing, you'll need to be using React with a supported bundler. See if your bundler is listed in the configuration guides below.
646
+
647
+ <!-- ::start:framework -->
648
+
649
+ # React
650
+
651
+ - [Installation with Vite](../installation/with-vite)
652
+ - [Installation with Rspack/Rsbuild](../installation/with-rspack)
653
+ - [Installation with Webpack](../installation/with-webpack)
654
+ - [Installation with Esbuild](../installation/with-esbuild)
655
+
656
+ # Solid
657
+
658
+ - [Installation with Vite](../installation/with-vite)
659
+ - [Installation with Rspack/Rsbuild](../installation/with-rspack)
660
+ - [Installation with Webpack](../installation/with-webpack)
661
+ - [Installation with Esbuild](../installation/with-esbuild)
662
+
663
+ <!-- ::end:framework -->
664
+
665
+ When using TanStack Router's file-based routing through one of the supported bundlers, our plugin will **automatically generate your route configuration through your bundler's dev and build processes**. It is the easiest way to use TanStack Router's route generation features.
666
+
667
+ If your bundler is not yet supported, you can reach out to us on Discord or GitHub to let us know.
668
+
669
+ # File Naming Conventions
670
+
671
+ File-based routing requires that you follow a few simple file naming conventions to ensure that your routes are generated correctly. The concepts these conventions enable are covered in detail in the [Route Trees & Nesting](./route-trees.md) guide.
672
+
673
+ | Feature | Description |
674
+ | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
675
+ | **\`__root.tsx\`** | The root route file must be named \`__root.tsx\` and must be placed in the root of the configured \`routesDirectory\`. |
676
+ | **\`.\` Separator** | Routes can use the \`.\` character to denote a nested route. For example, \`blog.post\` will be generated as a child of \`blog\`. |
677
+ | **\`$\` Token** | Route segments with the \`$\` token are parameterized and will extract the value from the URL pathname as a route \`param\`. |
678
+ | **\`_\` Prefix** | Route segments with the \`_\` prefix are considered to be pathless layout routes and will not be used when matching its child routes against the URL pathname. |
679
+ | **\`_\` Suffix** | Route segments with the \`_\` suffix exclude the route from being nested under any parent routes. |
680
+ | **\`-\` Prefix** | Files and folders with the \`-\` prefix are excluded from the route tree. They will not be added to the \`routeTree.gen.ts\` file and can be used to colocate logic in route folders. |
681
+ | **\`(folder)\` folder name pattern** | A folder that matches this pattern is treated as a **route group**, preventing the folder from being included in the route's URL path. |
682
+ | **\`[x]\` Escaping** | Square brackets escape special characters in filenames that would otherwise have routing meaning. For example, \`script[.]js.tsx\` becomes \`/script.js\` and \`api[.]v1.tsx\` becomes \`/api.v1\`. |
683
+ | **\`index\` Token** | Route segments ending with the \`index\` token (before any file extensions) will match the parent route when the URL pathname matches the parent route exactly. This can be configured via the \`indexToken\` configuration option (supports both strings and regex patterns), see [options](../api/file-based-routing.md#indextoken). |
684
+ | **\`.route.tsx\` File Type** | When using directories to organise routes, the \`route\` suffix can be used to create a route file at the directory's path. For example, \`blog.post.route.tsx\` or \`blog/post/route.tsx\` can be used as the route file for the \`/blog/post\` route. This can be configured via the \`routeToken\` configuration option (supports both strings and regex patterns), see [options](../api/file-based-routing.md#routetoken). |
685
+
686
+ > **💡 Remember:** The file-naming conventions for your project could be affected by what [options](../api/file-based-routing.md) are configured.
687
+
688
+ ## Dynamic Path Params
689
+
690
+ Dynamic path params can be used in both flat and directory routes to create routes that can match a dynamic segment of the URL path. Dynamic path params are denoted by the \`$\` character in the filename:
691
+
692
+ | Filename | Route Path | Component Output |
693
+ | --------------------- | ---------------- | --------------------- |
694
+ | ... | ... | ... |
695
+ | ʦ \`posts.$postId.tsx\` | \`/posts/$postId\` | \`<Root><Posts><Post>\` |
696
+
697
+ We'll learn more about dynamic path params in the [Path Params](../guide/path-params.md) guide.
698
+
699
+ ## Pathless Routes
700
+
701
+ Pathless routes wrap child routes with either logic or a component without requiring a URL path. Non-path routes are denoted by the \`_\` character in the filename:
702
+
703
+ | Filename | Route Path | Component Output |
704
+ | -------------- | ---------- | ---------------- |
705
+ | ʦ \`_app.tsx\` | | |
706
+ | ʦ \`_app.a.tsx\` | /a | \`<Root><App><A>\` |
707
+ | ʦ \`_app.b.tsx\` | /b | \`<Root><App><B>\` |
708
+
709
+ To learn more about pathless routes, see the [Routing Concepts - Pathless Routes](./routing-concepts.md#pathless-layout-routes) guide.
710
+
711
+ # Route Matching
712
+
713
+ Route matching follows a consistent and predictable pattern. This guide will explain how route trees are matched.
714
+
715
+ When TanStack Router processes your route tree, all of your routes are automatically sorted to match the most specific routes first. This means that regardless of the order your route tree is defined, routes will always be sorted in this order:
716
+
717
+ - Index Route
718
+ - Static Routes (most specific to least specific)
719
+ - Dynamic Routes (longest to shortest)
720
+ - Splat/Wildcard Routes
721
+
722
+ Consider the following pseudo route tree:
723
+
724
+ \`\`\`
725
+ Root
726
+ - blog
727
+ - $postId
728
+ - /
729
+ - new
730
+ - /
731
+ - *
732
+ - about
733
+ - about/us
734
+ \`\`\`
735
+
736
+ After sorting, this route tree will become:
737
+
738
+ \`\`\`
739
+ Root
740
+ - /
741
+ - about/us
742
+ - about
743
+ - blog
744
+ - /
745
+ - new
746
+ - $postId
747
+ - *
748
+ \`\`\`
749
+
750
+ This final order represents the order in which routes will be matched based on specificity.
751
+
752
+ Using that route tree, let's follow the matching process for a few different URLs:
753
+
754
+ - \`/blog\`
755
+ \`\`\`
756
+ Root
757
+ ❌ /
758
+ ❌ about/us
759
+ ❌ about
760
+ ⏩ blog
761
+ ✅ /
762
+ - new
763
+ - $postId
764
+ - *
765
+ \`\`\`
766
+ - \`/blog/my-post\`
767
+ \`\`\`
768
+ Root
769
+ ❌ /
770
+ ❌ about/us
771
+ ❌ about
772
+ ⏩ blog
773
+ ❌ /
774
+ ❌ new
775
+ ✅ $postId
776
+ - *
777
+ \`\`\`
778
+ - \`/\`
779
+ \`\`\`
780
+ Root
781
+ ✅ /
782
+ - about/us
783
+ - about
784
+ - blog
785
+ - /
786
+ - new
787
+ - $postId
788
+ - *
789
+ \`\`\`
790
+ - \`/not-a-route\`
791
+ \`\`\`
792
+ Root
793
+ ❌ /
794
+ ❌ about/us
795
+ ❌ about
796
+ ❌ blog
797
+ - /
798
+ - new
799
+ - $postId
800
+ ✅ *
801
+ \`\`\`
802
+
803
+ # Route Trees
804
+
805
+ TanStack Router uses a nested route tree to match up the URL with the correct component tree to render.
806
+
807
+ To build a route tree, TanStack Router supports:
808
+
809
+ - [File-Based Routing](./file-based-routing.md)
810
+ - [Code-Based Routing](./code-based-routing.md)
811
+
812
+ Both methods support the exact same core features and functionality, but **file-based routing requires less code for the same or better results**. For this reason, **file-based routing is the preferred and recommended way** to configure TanStack Router. Most of the documentation is written from the perspective of file-based routing.
813
+
814
+ ## Route Trees
815
+
816
+ Nested routing is a powerful concept that allows you to use a URL to render a nested component tree. For example, given the URL of \`/blog/posts/123\`, you could create a route hierarchy that looks like this:
817
+
818
+ \`\`\`tsx
819
+ ├── blog
820
+ │ ├── posts
821
+ │ │ ├── $postId
822
+ \`\`\`
823
+
824
+ And render a component tree that looks like this:
825
+
826
+ \`\`\`tsx
827
+ <Blog>
828
+ <Posts>
829
+ <Post postId="123" />
830
+ </Posts>
831
+ </Blog>
832
+ \`\`\`
833
+
834
+ Let's take that concept and expand it out to a larger site structure, but with file-names now:
835
+
836
+ \`\`\`
837
+ /routes
838
+ ├── __root.tsx
839
+ ├── index.tsx
840
+ ├── about.tsx
841
+ ├── posts/
842
+ │ ├── index.tsx
843
+ │ ├── $postId.tsx
844
+ ├── posts.$postId.edit.tsx
845
+ ├── settings/
846
+ │ ├── profile.tsx
847
+ │ ├── notifications.tsx
848
+ ├── _pathlessLayout/
849
+ │ ├── route-a.tsx
850
+ ├── ├── route-b.tsx
851
+ ├── files/
852
+ │ ├── $.tsx
853
+ \`\`\`
854
+
855
+ The above is a valid route tree configuration that can be used with TanStack Router! There's a lot of power and convention to unpack with file-based routing, so let's break it down a bit.
856
+
857
+ ## Route Tree Configuration
858
+
859
+ Route trees can be configured using a few different ways:
860
+
861
+ - [Flat Routes](./file-based-routing.md#flat-routes)
862
+ - [Directories](./file-based-routing.md#directory-routes)
863
+ - [Mixed Flat Routes and Directories](./file-based-routing.md#mixed-flat-and-directory-routes)
864
+ - [Virtual File Routes](./virtual-file-routes.md)
865
+ - [Code-Based Routes](./code-based-routing.md)
866
+
867
+ Please be sure to check out the full documentation links above for each type of route tree, or just proceed to the next section to get started with file-based routing.
868
+
869
+ # Routing Concepts
870
+
871
+ TanStack Router supports a number of powerful routing concepts that allow you to build complex and dynamic routing systems with ease.
872
+
873
+ Each of these concepts is useful and powerful, and we'll dive into each of them in the following sections.
874
+
875
+ ## Anatomy of a Route
876
+
877
+ All other routes, other than the [Root Route](#the-root-route), are configured using the \`createFileRoute\` function, which provides type safety when using file-based routing:
878
+
879
+ <!-- ::start:framework -->
880
+
881
+ # React
882
+
883
+ \`\`\`tsx title="src/routes/index.tsx"
884
+ import { createFileRoute } from '@tanstack/react-router'
885
+
886
+ export const Route = createFileRoute('/')({
887
+ component: PostsComponent,
888
+ })
889
+ \`\`\`
890
+
891
+ # Solid
892
+
893
+ \`\`\`tsx title="src/routes/index.tsx"
894
+ import { createFileRoute } from '@tanstack/solid-router'
895
+
896
+ export const Route = createFileRoute('/')({
897
+ component: PostsComponent,
898
+ })
899
+ \`\`\`
900
+
901
+ <!-- ::end:framework -->
902
+
903
+ The \`createFileRoute\` function takes a single argument, the file-route's path as a string.
904
+
905
+ **❓❓❓ "Wait, you're making me pass the path of the route file to \`createFileRoute\`?"**
906
+
907
+ Yes! But don't worry, this path is **automatically written and managed by the router for you via the TanStack Router Bundler Plugin or Router CLI.** So, as you create new routes, move routes around or rename routes, the path will be updated for you automatically.
908
+
909
+ The reason for this pathname has everything to do with the magical type safety of TanStack Router. Without this pathname, TypeScript would have no idea what file we're in! (We wish TypeScript had a built-in for this, but they don't yet 🤷‍♂️)
910
+
911
+ ## The Root Route
912
+
913
+ The root route is the top-most route in the entire tree and encapsulates all other routes as children.
914
+
915
+ - It has no path
916
+ - It is **always** matched
917
+ - Its \`component\` is **always** rendered
918
+
919
+ Even though it doesn't have a path, the root route has access to all of the same functionality as other routes including:
920
+
921
+ - components
922
+ - loaders
923
+ - search param validation
924
+ - etc.
925
+
926
+ To create a root route, call the \`createRootRoute()\` function and export it as the \`Route\` variable in your route file:
927
+
928
+ <!-- ::start:framework -->
929
+
930
+ # React
931
+
932
+ \`\`\`tsx
933
+ // Standard root route
934
+ import { createRootRoute } from '@tanstack/react-router'
935
+
936
+ export const Route = createRootRoute()
937
+
938
+ // Root route with Context
939
+ import { createRootRouteWithContext } from '@tanstack/react-router'
940
+ import type { QueryClient } from '@tanstack/react-query'
941
+
942
+ export interface MyRouterContext {
943
+ queryClient: QueryClient
944
+ }
945
+ export const Route = createRootRouteWithContext<MyRouterContext>()
946
+ \`\`\`
947
+
948
+ # Solid
949
+
950
+ \`\`\`tsx
951
+ // Standard root route
952
+ import { createRootRoute } from '@tanstack/solid-router'
953
+
954
+ export const Route = createRootRoute()
955
+
956
+ // Root route with Context
957
+ import { createRootRouteWithContext } from '@tanstack/solid-router'
958
+ import type { QueryClient } from '@tanstack/solid-query'
959
+
960
+ export interface MyRouterContext {
961
+ queryClient: QueryClient
962
+ }
963
+ export const Route = createRootRouteWithContext<MyRouterContext>()
964
+ \`\`\`
965
+
966
+ <!-- ::end:framework -->
967
+
968
+ To learn more about Context in TanStack Router, see the [Router Context](../guide/router-context.md) guide.
969
+
970
+ ## Basic Routes
971
+
972
+ Basic routes match a specific path, for example \`/about\`, \`/settings\`, \`/settings/notifications\` are all basic routes, as they match the path exactly.
973
+
974
+ Let's take a look at an \`/about\` route:
975
+
976
+ <!-- ::start:framework -->
977
+
978
+ # React
979
+
980
+ \`\`\`tsx title="src/routes/about.tsx"
981
+ import { createFileRoute } from '@tanstack/react-router'
982
+
983
+ export const Route = createFileRoute('/about')({
984
+ component: AboutComponent,
985
+ })
986
+
987
+ function AboutComponent() {
988
+ return <div>About</div>
989
+ }
990
+ \`\`\`
991
+
992
+ # Solid
993
+
994
+ \`\`\`tsx title="src/routes/about.tsx"
995
+ import { createFileRoute } from '@tanstack/solid-router'
996
+
997
+ export const Route = createFileRoute('/about')({
998
+ component: AboutComponent,
999
+ })
1000
+
1001
+ function AboutComponent() {
1002
+ return <div>About</div>
1003
+ }
1004
+ \`\`\`
1005
+
1006
+ <!-- ::end:framework -->
1007
+
1008
+ Basic routes are simple and straightforward. They match the path exactly and render the provided component.
1009
+
1010
+ ## Index Routes
1011
+
1012
+ Index routes specifically target their parent route when it is **matched exactly and no child route is matched**.
1013
+
1014
+ Let's take a look at an index route for a \`/posts\` URL:
1015
+
1016
+ <!-- ::start:framework -->
1017
+
1018
+ # React
1019
+
1020
+ \`\`\`tsx title="src/routes/posts.index.tsx"
1021
+ import { createFileRoute } from '@tanstack/react-router'
1022
+
1023
+ // Note the trailing slash, which is used to target index routes
1024
+ export const Route = createFileRoute('/posts/')({
1025
+ component: PostsIndexComponent,
1026
+ })
1027
+
1028
+ function PostsIndexComponent() {
1029
+ return <div>Please select a post!</div>
1030
+ }
1031
+ \`\`\`
1032
+
1033
+ # Solid
1034
+
1035
+ \`\`\`tsx title="src/routes/posts.index.tsx"
1036
+ import { createFileRoute } from '@tanstack/solid-router'
1037
+
1038
+ // Note the trailing slash, which is used to target index routes
1039
+ export const Route = createFileRoute('/posts/')({
1040
+ component: PostsIndexComponent,
1041
+ })
1042
+
1043
+ function PostsIndexComponent() {
1044
+ return <div>Please select a post!</div>
1045
+ }
1046
+ \`\`\`
1047
+
1048
+ <!-- ::end:framework -->
1049
+
1050
+ This route will be matched when the URL is \`/posts\` exactly.
1051
+
1052
+ ## Dynamic Route Segments
1053
+
1054
+ Route path segments that start with a \`$\` followed by a label are dynamic and capture that section of the URL into the \`params\` object for use in your application. For example, a pathname of \`/posts/123\` would match the \`/posts/$postId\` route, and the \`params\` object would be \`{ postId: '123' }\`.
1055
+
1056
+ These params are then usable in your route's configuration and components! Let's look at a \`posts.$postId.tsx\` route:
1057
+
1058
+ <!-- ::start:framework -->
1059
+
1060
+ # React
1061
+
1062
+ \`\`\`tsx title="src/routes/posts/$postId.tsx"
1063
+ import { createFileRoute } from '@tanstack/react-router'
1064
+
1065
+ export const Route = createFileRoute('/posts/$postId')({
1066
+ // In a loader
1067
+ loader: ({ params }) => fetchPost(params.postId),
1068
+ // Or in a component
1069
+ component: PostComponent,
1070
+ })
1071
+
1072
+ function PostComponent() {
1073
+ // In a component!
1074
+ const { postId } = Route.useParams()
1075
+ return <div>Post ID: {postId}</div>
1076
+ }
1077
+ \`\`\`
1078
+
1079
+ # Solid
1080
+
1081
+ \`\`\`tsx title="src/routes/posts.tsx"
1082
+ import { createFileRoute } from '@tanstack/solid-router'
1083
+
1084
+ export const Route = createFileRoute('/posts/$postId')({
1085
+ // In a loader
1086
+ loader: ({ params }) => fetchPost(params.postId),
1087
+ // Or in a component
1088
+ component: PostComponent,
1089
+ })
1090
+
1091
+ function PostComponent() {
1092
+ // In a component!
1093
+ const { postId } = Route.useParams()
1094
+ return <div>Post ID: {postId()}</div>
1095
+ }
1096
+ \`\`\`
1097
+
1098
+ <!-- ::end:framework -->
1099
+
1100
+ > 🧠 Dynamic segments work at **each** segment of the path. For example, you could have a route with the path of \`/posts/$postId/$revisionId\` and each \`$\` segment would be captured into the \`params\` object.
1101
+
1102
+ ## Splat / Catch-All Routes
1103
+
1104
+ A route with a path of only \`$\` is called a "splat" route because it _always_ captures _any_ remaining section of the URL pathname from the \`$\` to the end. The captured pathname is then available in the \`params\` object under the special \`_splat\` property.
1105
+
1106
+ For example, a route targeting the \`files/$\` path is a splat route. If the URL pathname is \`/files/documents/hello-world\`, the \`params\` object would contain \`documents/hello-world\` under the special \`_splat\` property:
1107
+
1108
+ \`\`\`js
1109
+ {
1110
+ '_splat': 'documents/hello-world'
1111
+ }
1112
+ \`\`\`
1113
+
1114
+ > ⚠️ In v1 of the router, splat routes are also denoted with a \`*\` instead of a \`_splat\` key for backwards compatibility. This will be removed in v2.
1115
+
1116
+ > 🧠 Why use \`$\`? Thanks to tools like Remix, we know that despite \`*\`s being the most common character to represent a wildcard, they do not play nice with filenames or CLI tools, so just like them, we decided to use \`$\` instead.
1117
+
1118
+ ## Optional Path Parameters
1119
+
1120
+ Optional path parameters allow you to define route segments that may or may not be present in the URL. They use the \`{-$paramName}\` syntax and provide flexible routing patterns where certain parameters are optional.
1121
+
1122
+ <!-- ::start:framework -->
1123
+
1124
+ # React
1125
+
1126
+ \`\`\`tsx title="src/routes/posts.{-$category}.tsx"
1127
+ // The \`-$category\` segment is optional, so this route matches both \`/posts\` and \`/posts/tech\`
1128
+ import { createFileRoute } from '@tanstack/react-router'
1129
+
1130
+ export const Route = createFileRoute('/posts/{-$category}')({
1131
+ component: PostsComponent,
1132
+ })
1133
+
1134
+ function PostsComponent() {
1135
+ const { category } = Route.useParams()
1136
+
1137
+ return <div>{category ? \`Posts in \${category}\` : 'All Posts'}</div>
1138
+ }
1139
+ \`\`\`
1140
+
1141
+ # Solid
1142
+
1143
+ \`\`\`tsx title="src/routes/posts.{-$category}.tsx"
1144
+ // The \`-$category\` segment is optional, so this route matches both \`/posts\` and \`/posts/tech\`
1145
+ import { createFileRoute } from '@tanstack/solid-router'
1146
+
1147
+ export const Route = createFileRoute('/posts/{-$category}')({
1148
+ component: PostsComponent,
1149
+ })
1150
+
1151
+ function PostsComponent() {
1152
+ const { category } = Route.useParams()
1153
+
1154
+ return <div>{category ? \`Posts in \${category()}\` : 'All Posts'}</div>
1155
+ }
1156
+ \`\`\`
1157
+
1158
+ <!-- ::end:framework -->
1159
+
1160
+ This route will match both \`/posts\` (category is \`undefined\`) and \`/posts/tech\` (category is \`"tech"\`).
1161
+
1162
+ You can also define multiple optional parameters in a single route:
1163
+
1164
+ <!-- ::start:framework -->
1165
+
1166
+ # React
1167
+
1168
+ \`\`\`tsx title="src/routes/posts.{-$category}.\${-$slug}.tsx"
1169
+ // The \`-$category\` segment is optional, so this route matches both \`/posts\` and \`/posts/tech\`
1170
+ import { createFileRoute } from '@tanstack/react-router'
1171
+
1172
+ export const Route = createFileRoute('/posts/{-$category}/{-$slug}')({
1173
+ component: PostsComponent,
1174
+ })
1175
+ \`\`\`
1176
+
1177
+ # Solid
1178
+
1179
+ \`\`\`tsx title="src/routes/posts.{-$category}.\${-$slug}.tsx"
1180
+ // The \`-$category\` segment is optional, so this route matches both \`/posts\` and \`/posts/tech\`
1181
+ import { createFileRoute } from '@tanstack/solid-router'
1182
+
1183
+ export const Route = createFileRoute('/posts/{-$category}/{-$slug}')({
1184
+ component: PostsComponent,
1185
+ })
1186
+ \`\`\`
1187
+
1188
+ <!-- ::end:framework -->
1189
+
1190
+ This route matches \`/posts\`, \`/posts/tech\`, and \`/posts/tech/hello-world\`.
1191
+
1192
+ > 🧠 Routes with optional parameters are ranked lower in priority than exact matches, ensuring that more specific routes like \`/posts/featured\` are matched before \`/posts/{-$category}\`.
1193
+
1194
+ ## Layout Routes
1195
+
1196
+ Layout routes are used to wrap child routes with additional components and logic. They are useful for:
1197
+
1198
+ - Wrapping child routes with a layout component
1199
+ - Enforcing a \`loader\` requirement before displaying any child routes
1200
+ - Validating and providing search params to child routes
1201
+ - Providing fallbacks for error components or pending elements to child routes
1202
+ - Providing shared context to all child routes
1203
+ - And more!
1204
+
1205
+ Let's take a look at an example layout route called \`app.tsx\`:
1206
+
1207
+ \`\`\`
1208
+ routes/
1209
+ ├── app.tsx
1210
+ ├── app.dashboard.tsx
1211
+ ├── app.settings.tsx
1212
+ \`\`\`
1213
+
1214
+ In the tree above, \`app.tsx\` is a layout route that wraps two child routes, \`app.dashboard.tsx\` and \`app.settings.tsx\`.
1215
+
1216
+ This tree structure is used to wrap the child routes with a layout component:
1217
+
1218
+ <!-- ::start:framework -->
1219
+
1220
+ # React
1221
+
1222
+ \`\`\`tsx title="src/routes/app.tsx"
1223
+ import { Outlet, createFileRoute } from '@tanstack/react-router'
1224
+
1225
+ export const Route = createFileRoute('/app')({
1226
+ component: AppLayoutComponent,
1227
+ })
1228
+
1229
+ function AppLayoutComponent() {
1230
+ return (
1231
+ <div>
1232
+ <h1>App Layout</h1>
1233
+ <Outlet />
1234
+ </div>
1235
+ )
1236
+ }
1237
+ \`\`\`
1238
+
1239
+ # Solid
1240
+
1241
+ \`\`\`tsx title="src/routes/app.tsx"
1242
+ import { Outlet, createFileRoute } from '@tanstack/solid-router'
1243
+
1244
+ export const Route = createFileRoute('/app')({
1245
+ component: AppLayoutComponent,
1246
+ })
1247
+
1248
+ function AppLayoutComponent() {
1249
+ return (
1250
+ <div>
1251
+ <h1>App Layout</h1>
1252
+ <Outlet />
1253
+ </div>
1254
+ )
1255
+ }
1256
+ \`\`\`
1257
+
1258
+ <!-- ::end:framework -->
1259
+
1260
+ The following table shows which component(s) will be rendered based on the URL:
1261
+
1262
+ | URL Path | Component |
1263
+ | ---------------- | ------------------------ |
1264
+ | \`/app\` | \`<AppLayout>\` |
1265
+ | \`/app/dashboard\` | \`<AppLayout><Dashboard>\` |
1266
+ | \`/app/settings\` | \`<AppLayout><Settings>\` |
1267
+
1268
+ Since TanStack Router supports mixed flat and directory routes, you can also express your application's routing using layout routes within directories:
1269
+
1270
+ \`\`\`
1271
+ routes/
1272
+ ├── app/
1273
+ │ ├── route.tsx
1274
+ │ ├── dashboard.tsx
1275
+ │ ├── settings.tsx
1276
+ \`\`\`
1277
+
1278
+ In this nested tree, the \`app/route.tsx\` file is a configuration for the layout route that wraps two child routes, \`app/dashboard.tsx\` and \`app/settings.tsx\`.
1279
+
1280
+ Layout Routes also let you enforce component and loader logic for Dynamic Route Segments:
1281
+
1282
+ \`\`\`
1283
+ routes/
1284
+ ├── app/users/
1285
+ │ ├── $userId/
1286
+ | | ├── route.tsx
1287
+ | | ├── index.tsx
1288
+ | | ├── edit.tsx
1289
+ \`\`\`
1290
+
1291
+ ## Pathless Layout Routes
1292
+
1293
+ Like [Layout Routes](#layout-routes), Pathless Layout Routes are used to wrap child routes with additional components and logic. However, pathless layout routes do not require a matching \`path\` in the URL and are used to wrap child routes with additional components and logic without requiring a matching \`path\` in the URL.
1294
+
1295
+ Pathless Layout Routes are prefixed with an underscore (\`_\`) to denote that they are "pathless".
1296
+
1297
+ > 🧠 The part of the path after the \`_\` prefix is used as the route's ID and is required because every route must be uniquely identifiable, especially when using TypeScript so as to avoid type errors and accomplish autocomplete effectively.
1298
+
1299
+ Let's take a look at an example route called \`_pathlessLayout.tsx\`:
1300
+
1301
+ \`\`\`
1302
+
1303
+ routes/
1304
+ ├── _pathlessLayout.tsx
1305
+ ├── _pathlessLayout.a.tsx
1306
+ ├── _pathlessLayout.b.tsx
1307
+
1308
+ \`\`\`
1309
+
1310
+ In the tree above, \`_pathlessLayout.tsx\` is a pathless layout route that wraps two child routes, \`_pathlessLayout.a.tsx\` and \`_pathlessLayout.b.tsx\`.
1311
+
1312
+ The \`_pathlessLayout.tsx\` route is used to wrap the child routes with a Pathless layout component:
1313
+
1314
+ <!-- ::start:framework -->
1315
+
1316
+ # React
1317
+
1318
+ \`\`\`tsx title="src/routes/_pathlessLayout.tsx"
1319
+ import { Outlet, createFileRoute } from '@tanstack/react-router'
1320
+
1321
+ export const Route = createFileRoute('/_pathlessLayout')({
1322
+ component: PathlessLayoutComponent,
1323
+ })
1324
+
1325
+ function PathlessLayoutComponent() {
1326
+ return (
1327
+ <div>
1328
+ <h1>Pathless layout</h1>
1329
+ <Outlet />
1330
+ </div>
1331
+ )
1332
+ }
1333
+ \`\`\`
1334
+
1335
+ # Solid
1336
+
1337
+ \`\`\`tsx title="src/routes/_pathlessLayout.tsx"
1338
+ import { Outlet, createFileRoute } from '@tanstack/solid-router'
1339
+
1340
+ export const Route = createFileRoute('/_pathlessLayout')({
1341
+ component: PathlessLayoutComponent,
1342
+ })
1343
+
1344
+ function PathlessLayoutComponent() {
1345
+ return (
1346
+ <div>
1347
+ <h1>Pathless layout</h1>
1348
+ <Outlet />
1349
+ </div>
1350
+ )
1351
+ }
1352
+ \`\`\`
1353
+
1354
+ <!-- ::end:framework -->
1355
+
1356
+ The following table shows which component will be rendered based on the URL:
1357
+
1358
+ | URL Path | Component |
1359
+ | -------- | --------------------- |
1360
+ | \`/\` | \`<Index>\` |
1361
+ | \`/a\` | \`<PathlessLayout><A>\` |
1362
+ | \`/b\` | \`<PathlessLayout><B>\` |
1363
+
1364
+ Since TanStack Router supports mixed flat and directory routes, you can also express your application's routing using pathless layout routes within directories:
1365
+
1366
+ \`\`\`
1367
+ routes/
1368
+ ├── _pathlessLayout/
1369
+ │ ├── route.tsx
1370
+ │ ├── a.tsx
1371
+ │ ├── b.tsx
1372
+ \`\`\`
1373
+
1374
+ However, unlike Layout Routes, since Pathless Layout Routes do not match based on URL path segments, this means that these routes do not support [Dynamic Route Segments](#dynamic-route-segments) as part of their path and therefore cannot be matched in the URL.
1375
+
1376
+ This means that you cannot do this:
1377
+
1378
+ \`\`\`
1379
+ routes/
1380
+ ├── _$postId/ ❌
1381
+ │ ├── ...
1382
+ \`\`\`
1383
+
1384
+ Rather, you'd have to do this:
1385
+
1386
+ \`\`\`
1387
+ routes/
1388
+ ├── $postId/
1389
+ ├── _postPathlessLayout/ ✅
1390
+ │ ├── ...
1391
+ \`\`\`
1392
+
1393
+ ## Non-Nested Routes
1394
+
1395
+ Non-nested routes can be created by suffixing a parent file route segment with a \`_\` and are used to **un-nest** a route from its parents and render its own component tree.
1396
+
1397
+ Consider the following flat route tree:
1398
+
1399
+ \`\`\`
1400
+ routes/
1401
+ ├── posts.tsx
1402
+ ├── posts.$postId.tsx
1403
+ ├── posts_.$postId.edit.tsx
1404
+ \`\`\`
1405
+
1406
+ The following table shows which component will be rendered based on the URL:
1407
+
1408
+ | URL Path | Component |
1409
+ | ----------------- | ---------------------------- |
1410
+ | \`/posts\` | \`<Posts>\` |
1411
+ | \`/posts/123\` | \`<Posts><Post postId="123">\` |
1412
+ | \`/posts/123/edit\` | \`<PostEditor postId="123">\` |
1413
+
1414
+ - The \`posts.$postId.tsx\` route is nested as normal under the \`posts.tsx\` route and will render \`<Posts><Post>\`.
1415
+ - The \`posts_.$postId.edit.tsx\` route **does not share** the same \`posts\` prefix as the other routes and therefore will be treated as if it is a top-level route and will render \`<PostEditor>\`.
1416
+
1417
+ ## Excluding Files and Folders from Routes
1418
+
1419
+ Files and folders can be excluded from route generation with a \`-\` prefix attached to the file name. This gives you the ability to colocate logic in the route directories.
1420
+
1421
+ Consider the following route tree:
1422
+
1423
+ \`\`\`
1424
+ routes/
1425
+ ├── posts.tsx
1426
+ ├── -posts-table.tsx // 👈🏼 ignored
1427
+ ├── -components/ // 👈🏼 ignored
1428
+ │ ├── header.tsx // 👈🏼 ignored
1429
+ │ ├── footer.tsx // 👈🏼 ignored
1430
+ │ ├── ...
1431
+ \`\`\`
1432
+
1433
+ We can import from the excluded files into our posts route
1434
+
1435
+ <!-- ::start:framework -->
1436
+
1437
+ # React
1438
+
1439
+ \`\`\`tsx title="src/routes/posts.tsx"
1440
+ import { createFileRoute } from '@tanstack/react-router'
1441
+ import { PostsTable } from './-posts-table'
1442
+ import { PostsHeader } from './-components/header'
1443
+ import { PostsFooter } from './-components/footer'
1444
+
1445
+ export const Route = createFileRoute('/posts')({
1446
+ loader: () => fetchPosts(),
1447
+ component: PostComponent,
1448
+ })
1449
+
1450
+ function PostComponent() {
1451
+ const posts = Route.useLoaderData()
1452
+
1453
+ return (
1454
+ <div>
1455
+ <PostsHeader />
1456
+ <PostsTable posts={posts} />
1457
+ <PostsFooter />
1458
+ </div>
1459
+ )
1460
+ }
1461
+ \`\`\`
1462
+
1463
+ # Solid
1464
+
1465
+ \`\`\`tsx title="src/routes/posts.tsx"
1466
+ import { createFileRoute } from '@tanstack/solid-router'
1467
+ import { PostsTable } from './-posts-table'
1468
+ import { PostsHeader } from './-components/header'
1469
+ import { PostsFooter } from './-components/footer'
1470
+
1471
+ export const Route = createFileRoute('/posts')({
1472
+ loader: () => fetchPosts(),
1473
+ component: PostComponent,
1474
+ })
1475
+
1476
+ function PostComponent() {
1477
+ const posts = Route.useLoaderData()
1478
+
1479
+ return (
1480
+ <div>
1481
+ <PostsHeader />
1482
+ <PostsTable posts={posts} />
1483
+ <PostsFooter />
1484
+ </div>
1485
+ )
1486
+ }
1487
+ \`\`\`
1488
+
1489
+ <!-- ::end:framework -->
1490
+
1491
+ The excluded files will not be added to \`routeTree.gen.ts\`.
1492
+
1493
+ ## Pathless Route Group Directories
1494
+
1495
+ Pathless route group directories use \`()\` as a way to group routes files together regardless of their path. They are purely organizational and do not affect the route tree or component tree in any way.
1496
+
1497
+ \`\`\`
1498
+ routes/
1499
+ ├── index.tsx
1500
+ ├── (app)/
1501
+ │ ├── dashboard.tsx
1502
+ │ ├── settings.tsx
1503
+ │ ├── users.tsx
1504
+ ├── (auth)/
1505
+ │ ├── login.tsx
1506
+ │ ├── register.tsx
1507
+ \`\`\`
1508
+
1509
+ In the example above, the \`app\` and \`auth\` directories are purely organizational and do not affect the route tree or component tree in any way. They are used to group related routes together for easier navigation and organization.
1510
+
1511
+ The following table shows which component will be rendered based on the URL:
1512
+
1513
+ | URL Path | Component |
1514
+ | ------------ | ------------- |
1515
+ | \`/\` | \`<Index>\` |
1516
+ | \`/dashboard\` | \`<Dashboard>\` |
1517
+ | \`/settings\` | \`<Settings>\` |
1518
+ | \`/users\` | \`<Users>\` |
1519
+ | \`/login\` | \`<Login>\` |
1520
+ | \`/register\` | \`<Register>\` |
1521
+
1522
+ As you can see, the \`app\` and \`auth\` directories are purely organizational and do not affect the route tree or component tree in any way.
1523
+
1524
+ # Virtual File Routes
1525
+
1526
+ > We'd like to thank the Remix team for [pioneering the concept of virtual file routes](https://www.youtube.com/watch?v=fjTX8hQTlEc&t=730s). We've taken inspiration from their work and adapted it to work with TanStack Router's existing file-based route-tree generation.
1527
+
1528
+ Virtual file routes are a powerful concept that allows you to build a route tree programmatically using code that references real files in your project. This can be useful if:
1529
+
1530
+ - You have an existing route organization that you want to keep.
1531
+ - You want to customize the location of your route files.
1532
+ - You want to completely override TanStack Router's file-based route generation and build your own convention.
1533
+
1534
+ Here's a quick example of using virtual file routes to map a route tree to a set of real files in your project:
1535
+
1536
+ \`\`\`tsx
1537
+ // routes.ts
1538
+ import {
1539
+ rootRoute,
1540
+ route,
1541
+ index,
1542
+ layout,
1543
+ physical,
1544
+ } from '@tanstack/virtual-file-routes'
1545
+
1546
+ export const routes = rootRoute('root.tsx', [
1547
+ index('index.tsx'),
1548
+ layout('pathlessLayout.tsx', [
1549
+ route('/dashboard', 'app/dashboard.tsx', [
1550
+ index('app/dashboard-index.tsx'),
1551
+ route('/invoices', 'app/dashboard-invoices.tsx', [
1552
+ index('app/invoices-index.tsx'),
1553
+ route('$id', 'app/invoice-detail.tsx'),
1554
+ ]),
1555
+ ]),
1556
+ physical('/posts', 'posts'),
1557
+ ]),
1558
+ ])
1559
+ \`\`\`
1560
+
1561
+ ## Configuration
1562
+
1563
+ Virtual file routes can be configured either via:
1564
+
1565
+ - The \`TanStackRouter\` plugin for Vite/Rspack/Webpack
1566
+ - The \`tsr.config.json\` file for the TanStack Router CLI
1567
+
1568
+ ## Configuration via the TanStackRouter Plugin
1569
+
1570
+ If you're using the \`TanStackRouter\` plugin for Vite/Rspack/Webpack, you can configure virtual file routes by passing the path of your routes file to the \`virtualRoutesConfig\` option when setting up the plugin:
1571
+
1572
+ <!-- ::start:framework -->
1573
+
1574
+ # React
1575
+
1576
+ \`\`\`tsx title="vite.config.ts"
1577
+ import { defineConfig } from 'vite'
1578
+ import react from '@vitejs/plugin-react'
1579
+ import { tanstackRouter } from '@tanstack/router-plugin/vite'
1580
+
1581
+ export default defineConfig({
1582
+ plugins: [
1583
+ tanstackRouter({
1584
+ target: 'react',
1585
+ virtualRouteConfig: './routes.ts',
1586
+ }),
1587
+ react(),
1588
+ ],
1589
+ })
1590
+ \`\`\`
1591
+
1592
+ # Solid
1593
+
1594
+ \`\`\`tsx title="vite.config.ts"
1595
+ import { defineConfig } from 'vite'
1596
+ import solid from 'vite-plugin-solid'
1597
+ import { tanstackRouter } from '@tanstack/router-plugin/vite'
1598
+
1599
+ export default defineConfig({
1600
+ plugins: [
1601
+ tanstackRouter({
1602
+ target: 'solid',
1603
+ virtualRouteConfig: './routes.ts',
1604
+ }),
1605
+ solid(),
1606
+ ],
1607
+ })
1608
+ \`\`\`
1609
+
1610
+ <!-- ::end:framework -->
1611
+
1612
+ Or, you choose to define the virtual routes directly in the configuration:
1613
+
1614
+ \`\`\`tsx
1615
+ // vite.config.ts
1616
+ import { defineConfig } from 'vite'
1617
+ import react from '@vitejs/plugin-react'
1618
+ import { tanstackRouter } from '@tanstack/router-plugin/vite'
1619
+ import { rootRoute } from '@tanstack/virtual-file-routes'
1620
+
1621
+ const routes = rootRoute('root.tsx', [
1622
+ // ... the rest of your virtual route tree
1623
+ ])
1624
+
1625
+ export default defineConfig({
1626
+ plugins: [tanstackRouter({ virtualRouteConfig: routes }), react()],
1627
+ })
1628
+ \`\`\`
1629
+
1630
+ <!-- ::start:framework -->
1631
+
1632
+ # React
1633
+
1634
+ \`\`\`tsx title="vite.config.ts"
1635
+ import { defineConfig } from 'vite'
1636
+ import react from '@vitejs/plugin-react'
1637
+ import { tanstackRouter } from '@tanstack/router-plugin/vite'
1638
+
1639
+ const routes = rootRoute('root.tsx', [
1640
+ // ... the rest of your virtual route tree
1641
+ ])
1642
+
1643
+ export default defineConfig({
1644
+ plugins: [
1645
+ tanstackRouter({ virtualRouteConfig: routes, target: 'react' }),
1646
+ react(),
1647
+ ],
1648
+ })
1649
+ \`\`\`
1650
+
1651
+ # Solid
1652
+
1653
+ \`\`\`tsx title="vite.config.ts"
1654
+ import { defineConfig } from 'vite'
1655
+ import solid from 'vite-plugin-solid'
1656
+ import { tanstackRouter } from '@tanstack/router-plugin/vite'
1657
+
1658
+ const routes = rootRoute('root.tsx', [
1659
+ // ... the rest of your virtual route tree
1660
+ ])
1661
+
1662
+ export default defineConfig({
1663
+ plugins: [
1664
+ tanstackRouter({ virtualRouteConfig: routes, target: 'solid' }),
1665
+ solid(),
1666
+ ],
1667
+ })
1668
+ \`\`\`
1669
+
1670
+ <!-- ::end:framework -->
1671
+
1672
+ ## Creating Virtual File Routes
1673
+
1674
+ To create virtual file routes, you'll need to import the \`@tanstack/virtual-file-routes\` package. This package provides a set of functions that allow you to create virtual routes that reference real files in your project. A few utility functions are exported from the package:
1675
+
1676
+ - \`rootRoute\` - Creates a virtual root route.
1677
+ - \`route\` - Creates a virtual route.
1678
+ - \`index\` - Creates a virtual index route.
1679
+ - \`layout\` - Creates a virtual pathless layout route.
1680
+ - \`physical\` - Creates a physical virtual route (more on this later).
1681
+
1682
+ ## Virtual Root Route
1683
+
1684
+ The \`rootRoute\` function is used to create a virtual root route. It takes a file name and an array of children routes. Here's an example of a virtual root route:
1685
+
1686
+ \`\`\`tsx
1687
+ // routes.ts
1688
+ import { rootRoute } from '@tanstack/virtual-file-routes'
1689
+
1690
+ export const routes = rootRoute('root.tsx', [
1691
+ // ... children routes
1692
+ ])
1693
+ \`\`\`
1694
+
1695
+ ## Virtual Route
1696
+
1697
+ The \`route\` function is used to create a virtual route. It takes a path, a file name, and an array of children routes. Here's an example of a virtual route:
1698
+
1699
+ \`\`\`tsx
1700
+ // routes.ts
1701
+ import { route } from '@tanstack/virtual-file-routes'
1702
+
1703
+ export const routes = rootRoute('root.tsx', [
1704
+ route('/about', 'about.tsx', [
1705
+ // ... children routes
1706
+ ]),
1707
+ ])
1708
+ \`\`\`
1709
+
1710
+ You can also define a virtual route without a file name. This allows to set a common path prefix for its children:
1711
+
1712
+ \`\`\`tsx
1713
+ // routes.ts
1714
+ import { route } from '@tanstack/virtual-file-routes'
1715
+
1716
+ export const routes = rootRoute('root.tsx', [
1717
+ route('/hello', [
1718
+ route('/world', 'world.tsx'), // full path will be "/hello/world"
1719
+ route('/universe', 'universe.tsx'), // full path will be "/hello/universe"
1720
+ ]),
1721
+ ])
1722
+ \`\`\`
1723
+
1724
+ ## Virtual Index Route
1725
+
1726
+ The \`index\` function is used to create a virtual index route. It takes a file name. Here's an example of a virtual index route:
1727
+
1728
+ \`\`\`tsx
1729
+ import { index } from '@tanstack/virtual-file-routes'
1730
+
1731
+ const routes = rootRoute('root.tsx', [index('index.tsx')])
1732
+ \`\`\`
1733
+
1734
+ ## Virtual Pathless Route
1735
+
1736
+ The \`layout\` function is used to create a virtual pathless route. It takes a file name, an array of children routes, and an optional pathless ID. Here's an example of a virtual pathless route:
1737
+
1738
+ \`\`\`tsx
1739
+ // routes.ts
1740
+ import { layout } from '@tanstack/virtual-file-routes'
1741
+
1742
+ export const routes = rootRoute('root.tsx', [
1743
+ layout('pathlessLayout.tsx', [
1744
+ // ... children routes
1745
+ ]),
1746
+ ])
1747
+ \`\`\`
1748
+
1749
+ You can also specify a pathless ID to give the route a unique identifier that is different from the filename:
1750
+
1751
+ \`\`\`tsx
1752
+ // routes.ts
1753
+ import { layout } from '@tanstack/virtual-file-routes'
1754
+
1755
+ export const routes = rootRoute('root.tsx', [
1756
+ layout('my-pathless-layout-id', 'pathlessLayout.tsx', [
1757
+ // ... children routes
1758
+ ]),
1759
+ ])
1760
+ \`\`\`
1761
+
1762
+ ## Physical Virtual Routes
1763
+
1764
+ Physical virtual routes are a way to "mount" a directory of good ol' TanStack Router File Based routing convention under a specific URL path. This can be useful if you are using virtual routes to customize a small portion of your route tree high up in the hierarchy, but want to use the standard file-based routing convention for sub-routes and directories.
1765
+
1766
+ Consider the following file structure:
1767
+
1768
+ \`\`\`
1769
+ /routes
1770
+ ├── root.tsx
1771
+ ├── index.tsx
1772
+ ├── pathlessLayout.tsx
1773
+ ├── app
1774
+ │ ├── dashboard.tsx
1775
+ │ ├── dashboard-index.tsx
1776
+ │ ├── dashboard-invoices.tsx
1777
+ │ ├── invoices-index.tsx
1778
+ │ ├── invoice-detail.tsx
1779
+ └── posts
1780
+ ├── index.tsx
1781
+ ├── $postId.tsx
1782
+ ├── $postId.edit.tsx
1783
+ ├── comments/
1784
+ │ ├── index.tsx
1785
+ │ ├── $commentId.tsx
1786
+ └── likes/
1787
+ ├── index.tsx
1788
+ ├── $likeId.tsx
1789
+ \`\`\`
1790
+
1791
+ Let's use virtual routes to customize our route tree for everything but \`posts\`, then use physical virtual routes to mount the \`posts\` directory under the \`/posts\` path:
1792
+
1793
+ \`\`\`tsx
1794
+ // routes.ts
1795
+ export const routes = rootRoute('root.tsx', [
1796
+ // Set up your virtual routes as normal
1797
+ index('index.tsx'),
1798
+ layout('pathlessLayout.tsx', [
1799
+ route('/dashboard', 'app/dashboard.tsx', [
1800
+ index('app/dashboard-index.tsx'),
1801
+ route('/invoices', 'app/dashboard-invoices.tsx', [
1802
+ index('app/invoices-index.tsx'),
1803
+ route('$id', 'app/invoice-detail.tsx'),
1804
+ ]),
1805
+ ]),
1806
+ // Mount the \`posts\` directory under the \`/posts\` path
1807
+ physical('/posts', 'posts'),
1808
+ ]),
1809
+ ])
1810
+ \`\`\`
1811
+
1812
+ ### Merging Physical Routes at Current Level
1813
+
1814
+ You can also use \`physical\` with an empty path prefix (or a single argument) to merge routes from a physical directory directly at the current level, without adding a path prefix. This is useful when you want to organize your routes into separate directories but have them appear at the same URL level.
1815
+
1816
+ Consider the following file structure:
1817
+
1818
+ \`\`\`
1819
+ /routes
1820
+ ├── __root.tsx
1821
+ ├── about.tsx
1822
+ └── features
1823
+ ├── index.tsx
1824
+ └── contact.tsx
1825
+ \`\`\`
1826
+
1827
+ You can merge the \`features\` directory routes at the root level:
1828
+
1829
+ \`\`\`tsx
1830
+ // routes.ts
1831
+ import { physical, rootRoute, route } from '@tanstack/virtual-file-routes'
1832
+
1833
+ export const routes = rootRoute('__root.tsx', [
1834
+ route('/about', 'about.tsx'),
1835
+ // Merge features/ routes at root level (no path prefix)
1836
+ physical('features'),
1837
+ // Or equivalently: physical('', 'features')
1838
+ ])
1839
+ \`\`\`
1840
+
1841
+ This will produce the following routes:
1842
+
1843
+ - \`/about\` - from \`about.tsx\`
1844
+ - \`/\` - from \`features/index.tsx\`
1845
+ - \`/contact\` - from \`features/contact.tsx\`
1846
+
1847
+ > **Note:** When merging at the same level, ensure there are no conflicting route paths between your virtual routes and the physical directory routes. If a conflict occurs (e.g., both have an \`/about\` route), the generator will throw an error.
1848
+
1849
+ ## Virtual Routes inside of TanStack Router File Based routing
1850
+
1851
+ The previous section showed you how you can use TanStack Router's File Based routing convention inside of a virtual route configuration.
1852
+ However, the opposite is possible as well.
1853
+ You can configure the main part of your app's route tree using TanStack Router's File Based routing convention and opt into virtual route configuration for specific subtrees.
1854
+
1855
+ Consider the following file structure:
1856
+
1857
+ \`\`\`
1858
+ /routes
1859
+ ├── __root.tsx
1860
+ ├── foo
1861
+ │ ├── bar
1862
+ │ │ ├── __virtual.ts
1863
+ │ │ ├── details.tsx
1864
+ │ │ ├── home.tsx
1865
+ │ │ └── route.ts
1866
+ │ └── bar.tsx
1867
+ └── index.tsx
1868
+ \`\`\`
1869
+
1870
+ Let's look at the \`bar\` directory which contains a special file named \`__virtual.ts\`. This file instructs the generator to switch over to virtual file route configuration for this directory (and its child directories).
1871
+
1872
+ \`__virtual.ts\` configures the virtual routes for that particular subtree of the route tree. It uses the same API as explained above, with the only difference being that no \`rootRoute\` is defined for that subtree:
1873
+
1874
+ \`\`\`tsx
1875
+ // routes/foo/bar/__virtual.ts
1876
+ import {
1877
+ defineVirtualSubtreeConfig,
1878
+ index,
1879
+ route,
1880
+ } from '@tanstack/virtual-file-routes'
1881
+
1882
+ export default defineVirtualSubtreeConfig([
1883
+ index('home.tsx'),
1884
+ route('$id', 'details.tsx'),
1885
+ ])
1886
+ \`\`\`
1887
+
1888
+ The helper function \`defineVirtualSubtreeConfig\` is closely modeled after vite's \`defineConfig\` and allows you to define a subtree configuration via a default export. The default export can either be
1889
+
1890
+ - a subtree config object
1891
+ - a function returning a subtree config object
1892
+ - an async function returning a subtree config object
1893
+
1894
+ ## Inception
1895
+
1896
+ You can mix and match TanStack Router's File Based routing convention and virtual route configuration however you like.
1897
+ Let's go deeper!
1898
+ Check out the following example that starts off using File Based routing convention, switches over to virtual route configuration for \`/posts\`, switches back to File Based routing convention for \`/posts/lets-go\` only to switch over to virtual route configuration again for \`/posts/lets-go/deeper\`.
1899
+
1900
+ \`\`\`
1901
+ ├── __root.tsx
1902
+ ├── index.tsx
1903
+ ├── posts
1904
+ │ ├── __virtual.ts
1905
+ │ ├── details.tsx
1906
+ │ ├── home.tsx
1907
+ │ └── lets-go
1908
+ │ ├── deeper
1909
+ │ │ ├── __virtual.ts
1910
+ │ │ └── home.tsx
1911
+ │ └── index.tsx
1912
+ └── posts.tsx
1913
+ \`\`\`
1914
+
1915
+ ## Configuration via the TanStack Router CLI
1916
+
1917
+ If you're using the TanStack Router CLI, you can configure virtual file routes by defining the path to your routes file in the \`tsr.config.json\` file:
1918
+
1919
+ \`\`\`json
1920
+ // tsr.config.json
1921
+ {
1922
+ "virtualRouteConfig": "./routes.ts"
1923
+ }
1924
+ \`\`\`
1925
+
1926
+ Or you can define the virtual routes directly in the configuration, while much less common allows you to configure them via the TanStack Router CLI by adding a \`virtualRouteConfig\` object to your \`tsr.config.json\` file and defining your virtual routes and passing the resulting JSON that is generated by calling the actual \`rootRoute\`/\`route\`/\`index\`/etc functions from the \`@tanstack/virtual-file-routes\` package:
1927
+
1928
+ \`\`\`json
1929
+ // tsr.config.json
1930
+ {
1931
+ "virtualRouteConfig": {
1932
+ "type": "root",
1933
+ "file": "root.tsx",
1934
+ "children": [
1935
+ {
1936
+ "type": "index",
1937
+ "file": "home.tsx"
1938
+ },
1939
+ {
1940
+ "type": "route",
1941
+ "file": "posts/posts.tsx",
1942
+ "path": "/posts",
1943
+ "children": [
1944
+ {
1945
+ "type": "index",
1946
+ "file": "posts/posts-home.tsx"
1947
+ },
1948
+ {
1949
+ "type": "route",
1950
+ "file": "posts/posts-detail.tsx",
1951
+ "path": "$postId"
1952
+ }
1953
+ ]
1954
+ },
1955
+ {
1956
+ "type": "layout",
1957
+ "id": "first",
1958
+ "file": "layout/first-pathless-layout.tsx",
1959
+ "children": [
1960
+ {
1961
+ "type": "layout",
1962
+ "id": "second",
1963
+ "file": "layout/second-pathless-layout.tsx",
1964
+ "children": [
1965
+ {
1966
+ "type": "route",
1967
+ "file": "a.tsx",
1968
+ "path": "/route-a"
1969
+ },
1970
+ {
1971
+ "type": "route",
1972
+ "file": "b.tsx",
1973
+ "path": "/route-b"
1974
+ }
1975
+ ]
1976
+ }
1977
+ ]
1978
+ }
1979
+ ]
1980
+ }
1981
+ }
1982
+ \`\`\`
1983
+
1984
+ `;