react-router 8.4.0 → 8.5.1

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 (233) hide show
  1. package/CHANGELOG.md +94 -1
  2. package/dist/development/dom-export.d.ts +2 -1
  3. package/dist/development/dom-export.js +1 -1
  4. package/dist/development/index-react-server-client.js +2 -2
  5. package/dist/development/index-react-server.d.ts +237 -165
  6. package/dist/development/index-react-server.js +69 -33
  7. package/dist/development/index.d.ts +9 -8
  8. package/dist/development/index.js +5 -4
  9. package/dist/development/lib/actions.js +1 -1
  10. package/dist/development/lib/await.js +58 -0
  11. package/dist/development/lib/components.d.ts +41 -5
  12. package/dist/development/lib/components.js +82 -5
  13. package/dist/development/lib/context.d.ts +8 -3
  14. package/dist/development/lib/context.js +1 -1
  15. package/dist/development/lib/dom/dom.d.ts +3 -0
  16. package/dist/development/lib/dom/dom.js +1 -1
  17. package/dist/development/lib/dom/lib.d.ts +34 -9
  18. package/dist/development/lib/dom/lib.js +17 -6
  19. package/dist/development/lib/dom/server.js +2 -2
  20. package/dist/development/lib/dom/ssr/components.js +12 -9
  21. package/dist/development/lib/dom/ssr/data.js +1 -1
  22. package/dist/development/lib/dom/ssr/entry.d.ts +9 -2
  23. package/dist/development/lib/dom/ssr/errorBoundaries.js +1 -1
  24. package/dist/development/lib/dom/ssr/fallback.js +1 -1
  25. package/dist/development/lib/dom/ssr/fog-of-war.d.ts +3 -2
  26. package/dist/development/lib/dom/ssr/fog-of-war.js +25 -13
  27. package/dist/development/lib/dom/ssr/hydration.js +1 -1
  28. package/dist/development/lib/dom/ssr/invariant.js +1 -1
  29. package/dist/development/lib/dom/ssr/links.js +1 -1
  30. package/dist/development/lib/dom/ssr/markup.js +1 -1
  31. package/dist/development/lib/dom/ssr/route-discovery.d.ts +120 -0
  32. package/dist/development/lib/dom/ssr/route-discovery.js +415 -0
  33. package/dist/development/lib/dom/ssr/routeModules.js +1 -1
  34. package/dist/development/lib/dom/ssr/routes-test-stub.js +2 -2
  35. package/dist/development/lib/dom/ssr/routes.d.ts +2 -2
  36. package/dist/development/lib/dom/ssr/routes.js +8 -8
  37. package/dist/development/lib/dom/ssr/server.js +3 -1
  38. package/dist/development/lib/dom/ssr/single-fetch.d.ts +28 -2
  39. package/dist/development/lib/dom/ssr/single-fetch.js +73 -55
  40. package/dist/development/lib/dom-export/dom-router-provider.js +1 -1
  41. package/dist/development/lib/dom-export/hydrated-router.d.ts +28 -0
  42. package/dist/development/lib/dom-export/hydrated-router.js +32 -12
  43. package/dist/development/lib/errors.js +1 -1
  44. package/dist/development/lib/hooks.d.ts +3 -6
  45. package/dist/development/lib/hooks.js +8 -9
  46. package/dist/development/lib/href.js +1 -1
  47. package/dist/development/lib/router/history.js +1 -1
  48. package/dist/development/lib/router/instrumentation.js +1 -1
  49. package/dist/development/lib/router/matcher-route-pattern.js +1 -1
  50. package/dist/development/lib/router/matcher-route-pattern.preload.js +1 -1
  51. package/dist/development/lib/router/matcher.js +6 -1
  52. package/dist/development/lib/router/navigation.js +1 -1
  53. package/dist/development/lib/router/router.d.ts +8 -0
  54. package/dist/development/lib/router/router.js +213 -91
  55. package/dist/development/lib/router/url.js +1 -1
  56. package/dist/development/lib/router/utils.d.ts +31 -4
  57. package/dist/development/lib/router/utils.js +4 -3
  58. package/dist/development/lib/rsc/browser.js +4 -4
  59. package/dist/development/lib/rsc/errorBoundaries.js +1 -1
  60. package/dist/development/lib/rsc/html-stream/browser.js +1 -1
  61. package/dist/development/lib/rsc/html-stream/server.js +24 -12
  62. package/dist/development/lib/rsc/route-modules.js +1 -1
  63. package/dist/development/lib/rsc/server.rsc.d.ts +3 -2
  64. package/dist/development/lib/rsc/server.ssr.js +1 -1
  65. package/dist/development/lib/server-runtime/build.d.ts +14 -0
  66. package/dist/development/lib/server-runtime/cookies.js +1 -1
  67. package/dist/development/lib/server-runtime/crypto.js +1 -1
  68. package/dist/development/lib/server-runtime/data.js +1 -1
  69. package/dist/development/lib/server-runtime/dev.js +1 -1
  70. package/dist/development/lib/server-runtime/entry.js +1 -1
  71. package/dist/development/lib/server-runtime/errors.js +1 -1
  72. package/dist/development/lib/server-runtime/headers.js +1 -1
  73. package/dist/development/lib/server-runtime/invariant.js +1 -1
  74. package/dist/development/lib/server-runtime/mode.js +1 -1
  75. package/dist/development/lib/server-runtime/routeMatching.js +1 -1
  76. package/dist/development/lib/server-runtime/routes.d.ts +1 -1
  77. package/dist/development/lib/server-runtime/routes.js +1 -1
  78. package/dist/development/lib/server-runtime/server.js +24 -8
  79. package/dist/development/lib/server-runtime/serverHandoff.d.ts +17 -0
  80. package/dist/development/lib/server-runtime/serverHandoff.js +1 -1
  81. package/dist/development/lib/server-runtime/sessions/cookieStorage.js +1 -1
  82. package/dist/development/lib/server-runtime/sessions/memoryStorage.js +1 -1
  83. package/dist/development/lib/server-runtime/sessions.js +2 -2
  84. package/dist/development/lib/server-runtime/single-fetch.js +1 -1
  85. package/dist/development/lib/server-runtime/urls.js +1 -1
  86. package/dist/development/lib/server-runtime/warnings.js +1 -1
  87. package/dist/development/lib/types/internal.js +1 -1
  88. package/dist/development/lib/types/route-data.d.ts +2 -2
  89. package/dist/development/lib/types/route-module-annotations.d.ts +1 -1
  90. package/dist/development/route-pattern.js +1 -1
  91. package/dist/development/vendor/turbo-stream-v2/flatten.js +1 -1
  92. package/dist/development/vendor/turbo-stream-v2/turbo-stream.js +1 -1
  93. package/dist/development/vendor/turbo-stream-v2/unflatten.js +23 -3
  94. package/dist/development/vendor/turbo-stream-v2/utils.js +1 -1
  95. package/dist/production/dom-export.d.ts +2 -1
  96. package/dist/production/dom-export.js +1 -1
  97. package/dist/production/index-react-server-client.js +2 -2
  98. package/dist/production/index-react-server.d.ts +237 -165
  99. package/dist/production/index-react-server.js +69 -33
  100. package/dist/production/index.d.ts +9 -8
  101. package/dist/production/index.js +5 -4
  102. package/dist/production/lib/actions.js +1 -1
  103. package/dist/production/lib/await.js +58 -0
  104. package/dist/production/lib/components.d.ts +41 -5
  105. package/dist/production/lib/components.js +82 -5
  106. package/dist/production/lib/context.d.ts +8 -3
  107. package/dist/production/lib/context.js +1 -1
  108. package/dist/production/lib/dom/dom.d.ts +3 -0
  109. package/dist/production/lib/dom/dom.js +1 -1
  110. package/dist/production/lib/dom/lib.d.ts +34 -9
  111. package/dist/production/lib/dom/lib.js +17 -6
  112. package/dist/production/lib/dom/server.js +2 -2
  113. package/dist/production/lib/dom/ssr/components.js +12 -9
  114. package/dist/production/lib/dom/ssr/data.js +1 -1
  115. package/dist/production/lib/dom/ssr/entry.d.ts +9 -2
  116. package/dist/production/lib/dom/ssr/errorBoundaries.js +1 -1
  117. package/dist/production/lib/dom/ssr/fallback.js +1 -1
  118. package/dist/production/lib/dom/ssr/fog-of-war.d.ts +3 -2
  119. package/dist/production/lib/dom/ssr/fog-of-war.js +25 -13
  120. package/dist/production/lib/dom/ssr/hydration.js +1 -1
  121. package/dist/production/lib/dom/ssr/invariant.js +1 -1
  122. package/dist/production/lib/dom/ssr/links.js +1 -1
  123. package/dist/production/lib/dom/ssr/markup.js +1 -1
  124. package/dist/production/lib/dom/ssr/route-discovery.d.ts +120 -0
  125. package/dist/production/lib/dom/ssr/route-discovery.js +415 -0
  126. package/dist/production/lib/dom/ssr/routeModules.js +1 -1
  127. package/dist/production/lib/dom/ssr/routes-test-stub.js +2 -2
  128. package/dist/production/lib/dom/ssr/routes.d.ts +2 -2
  129. package/dist/production/lib/dom/ssr/routes.js +8 -8
  130. package/dist/production/lib/dom/ssr/server.js +3 -1
  131. package/dist/production/lib/dom/ssr/single-fetch.d.ts +28 -2
  132. package/dist/production/lib/dom/ssr/single-fetch.js +73 -55
  133. package/dist/production/lib/dom-export/dom-router-provider.js +1 -1
  134. package/dist/production/lib/dom-export/hydrated-router.d.ts +28 -0
  135. package/dist/production/lib/dom-export/hydrated-router.js +32 -12
  136. package/dist/production/lib/errors.js +1 -1
  137. package/dist/production/lib/hooks.d.ts +3 -6
  138. package/dist/production/lib/hooks.js +7 -8
  139. package/dist/production/lib/href.js +1 -1
  140. package/dist/production/lib/router/history.js +1 -1
  141. package/dist/production/lib/router/instrumentation.js +1 -1
  142. package/dist/production/lib/router/matcher-route-pattern.js +1 -1
  143. package/dist/production/lib/router/matcher-route-pattern.preload.js +1 -1
  144. package/dist/production/lib/router/matcher.js +6 -1
  145. package/dist/production/lib/router/navigation.js +1 -1
  146. package/dist/production/lib/router/router.d.ts +8 -0
  147. package/dist/production/lib/router/router.js +213 -91
  148. package/dist/production/lib/router/url.js +1 -1
  149. package/dist/production/lib/router/utils.d.ts +31 -4
  150. package/dist/production/lib/router/utils.js +4 -3
  151. package/dist/production/lib/rsc/browser.js +4 -4
  152. package/dist/production/lib/rsc/errorBoundaries.js +1 -1
  153. package/dist/production/lib/rsc/html-stream/browser.js +1 -1
  154. package/dist/production/lib/rsc/html-stream/server.js +24 -12
  155. package/dist/production/lib/rsc/route-modules.js +1 -1
  156. package/dist/production/lib/rsc/server.rsc.d.ts +3 -2
  157. package/dist/production/lib/rsc/server.ssr.js +1 -1
  158. package/dist/production/lib/server-runtime/build.d.ts +14 -0
  159. package/dist/production/lib/server-runtime/cookies.js +1 -1
  160. package/dist/production/lib/server-runtime/crypto.js +1 -1
  161. package/dist/production/lib/server-runtime/data.js +1 -1
  162. package/dist/production/lib/server-runtime/dev.js +1 -1
  163. package/dist/production/lib/server-runtime/entry.js +1 -1
  164. package/dist/production/lib/server-runtime/errors.js +1 -1
  165. package/dist/production/lib/server-runtime/headers.js +1 -1
  166. package/dist/production/lib/server-runtime/invariant.js +1 -1
  167. package/dist/production/lib/server-runtime/mode.js +1 -1
  168. package/dist/production/lib/server-runtime/routeMatching.js +1 -1
  169. package/dist/production/lib/server-runtime/routes.d.ts +1 -1
  170. package/dist/production/lib/server-runtime/routes.js +1 -1
  171. package/dist/production/lib/server-runtime/server.js +24 -8
  172. package/dist/production/lib/server-runtime/serverHandoff.d.ts +17 -0
  173. package/dist/production/lib/server-runtime/serverHandoff.js +1 -1
  174. package/dist/production/lib/server-runtime/sessions/cookieStorage.js +1 -1
  175. package/dist/production/lib/server-runtime/sessions/memoryStorage.js +1 -1
  176. package/dist/production/lib/server-runtime/sessions.js +2 -2
  177. package/dist/production/lib/server-runtime/single-fetch.js +1 -1
  178. package/dist/production/lib/server-runtime/urls.js +1 -1
  179. package/dist/production/lib/server-runtime/warnings.js +1 -1
  180. package/dist/production/lib/types/internal.js +1 -1
  181. package/dist/production/lib/types/route-data.d.ts +2 -2
  182. package/dist/production/lib/types/route-module-annotations.d.ts +1 -1
  183. package/dist/production/route-pattern.js +1 -1
  184. package/dist/production/vendor/turbo-stream-v2/flatten.js +1 -1
  185. package/dist/production/vendor/turbo-stream-v2/turbo-stream.js +1 -1
  186. package/dist/production/vendor/turbo-stream-v2/unflatten.js +23 -3
  187. package/dist/production/vendor/turbo-stream-v2/utils.js +1 -1
  188. package/docs/explanation/backend-for-frontend.md +0 -3
  189. package/docs/explanation/code-splitting.md +0 -3
  190. package/docs/explanation/concurrency.md +0 -3
  191. package/docs/explanation/hot-module-replacement.md +0 -3
  192. package/docs/explanation/lazy-route-discovery.md +4 -3
  193. package/docs/explanation/progressive-enhancement.md +0 -3
  194. package/docs/explanation/race-conditions.md +0 -3
  195. package/docs/explanation/react-transitions.md +0 -3
  196. package/docs/explanation/sessions-and-cookies.md +109 -5
  197. package/docs/explanation/state-management.md +0 -3
  198. package/docs/explanation/styling.md +0 -3
  199. package/docs/explanation/type-safety.md +0 -3
  200. package/docs/how-to/accessibility.md +0 -6
  201. package/docs/how-to/client-data.md +0 -3
  202. package/docs/how-to/custom-fetch.md +218 -0
  203. package/docs/how-to/data-strategy.md +23 -4
  204. package/docs/how-to/error-boundary.md +0 -3
  205. package/docs/how-to/error-reporting.md +0 -3
  206. package/docs/how-to/fetchers.md +0 -3
  207. package/docs/how-to/file-route-conventions.md +0 -3
  208. package/docs/how-to/file-uploads.md +0 -3
  209. package/docs/how-to/form-validation.md +0 -3
  210. package/docs/how-to/headers.md +0 -3
  211. package/docs/how-to/instrumentation.md +0 -3
  212. package/docs/how-to/middleware.md +7 -3
  213. package/docs/how-to/navigation-blocking.md +0 -3
  214. package/docs/how-to/optimize-revalidation.md +2 -5
  215. package/docs/how-to/pre-rendering.md +23 -4
  216. package/docs/how-to/presets.md +0 -3
  217. package/docs/how-to/react-server-components.md +0 -3
  218. package/docs/how-to/resource-routes.md +0 -3
  219. package/docs/how-to/route-discovery.md +147 -0
  220. package/docs/how-to/route-module-type-safety.md +0 -3
  221. package/docs/how-to/security.md +0 -3
  222. package/docs/how-to/server-bundles.md +0 -3
  223. package/docs/how-to/spa.md +2 -3
  224. package/docs/how-to/status.md +0 -3
  225. package/docs/how-to/suspense.md +22 -6
  226. package/docs/how-to/using-handle.md +0 -3
  227. package/docs/how-to/view-transitions.md +79 -15
  228. package/docs/start/framework/data-loading.md +9 -0
  229. package/docs/start/framework/navigating.md +5 -9
  230. package/docs/start/framework/rendering.md +37 -0
  231. package/docs/upgrading/future.md +0 -12
  232. package/docs/upgrading/v7.md +3 -33
  233. package/package.json +9 -1
@@ -6,9 +6,6 @@ title: Error Reporting
6
6
 
7
7
  [MODES: framework,data]
8
8
 
9
- <br/>
10
- <br/>
11
-
12
9
  React Router catches errors in your route modules and sends them to [error boundaries](./error-boundary) to prevent blank pages when errors occur. However, `ErrorBoundary` isn't sufficient for logging and reporting errors.
13
10
 
14
11
  ## Server Errors
@@ -6,9 +6,6 @@ title: Using Fetchers
6
6
 
7
7
  [MODES: framework, data]
8
8
 
9
- <br/>
10
- <br/>
11
-
12
9
  Fetchers are useful for creating complex, dynamic user interfaces that require multiple, concurrent data interactions without causing a navigation.
13
10
 
14
11
  Fetchers track their own, independent state and can be used to load data, mutate data, submit forms, and generally interact with loaders and actions.
@@ -6,9 +6,6 @@ title: File Route Conventions
6
6
 
7
7
  [MODES: framework]
8
8
 
9
- <br/>
10
- <br/>
11
-
12
9
  The `@react-router/fs-routes` package enables file-convention based route config.
13
10
 
14
11
  ## Setting up
@@ -6,9 +6,6 @@ title: File Uploads
6
6
 
7
7
  [MODES: framework]
8
8
 
9
- <br/>
10
- <br/>
11
-
12
9
  _Thank you to David Adams for [writing an original guide](https://programmingarehard.com/2024/09/06/remix-file-uploads-updated.html/) on which this doc is based. You can refer to it for even more examples._
13
10
 
14
11
  ## Basic File Upload
@@ -6,9 +6,6 @@ title: Form Validation
6
6
 
7
7
  [MODES: framework, data]
8
8
 
9
- <br/>
10
- <br/>
11
-
12
9
  This guide walks through a simple signup form implementation. You will likely want to pair these concepts with third-party validation libraries and error components, but this guide only focuses on the moving pieces for React Router.
13
10
 
14
11
  ## 1. Setting Up
@@ -6,9 +6,6 @@ title: HTTP Headers
6
6
 
7
7
  [MODES: framework]
8
8
 
9
- <br/>
10
- <br/>
11
-
12
9
  ## Reading request headers
13
10
 
14
11
  The `request` sent to route handlers is a standard Web Fetch [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request), so you can read headers directly from the [`request.headers`](https://developer.mozilla.org/en-US/docs/Web/API/Request/headers) property:
@@ -6,9 +6,6 @@ title: Instrumentation
6
6
 
7
7
  [MODES: framework, data]
8
8
 
9
- <br/>
10
- <br/>
11
-
12
9
  Instrumentation allows you to add logging, error reporting, and performance tracing to your React Router application without modifying your actual route handlers. This enables comprehensive observability solutions for production applications on both the server and client.
13
10
 
14
11
  ## Overview
@@ -6,9 +6,6 @@ title: Middleware
6
6
 
7
7
  [MODES: framework, data]
8
8
 
9
- <br/>
10
- <br/>
11
-
12
9
  Middleware allows you to run code before and after the [`Response`][Response] generation for the matched path. This enables [common patterns][common-patterns] like authentication, logging, error handling, and data preprocessing in a reusable way.
13
10
 
14
11
  Middleware runs in a nested chain, executing from parent routes to child routes on the way "down" to your route handlers, then from child routes back to parent routes on the way "up" after a [`Response`][Response] is generated.
@@ -474,6 +471,12 @@ Which `ErrorBoundary` is rendered will differ based on whether your middleware t
474
471
 
475
472
  ### Authentication
476
473
 
474
+ Middleware on a protected route or a common ancestor can authenticate and authorize a request before the matched loaders and actions run.
475
+
476
+ Loaders run in parallel and can be requested independently, so parent loaders are not capable of "protecting" child route loaders or actions. Each protected loader and action must perform its own checks unless appropriate server middleware enforces them before the handler runs.
477
+
478
+ <docs-warning>Attach authorization middleware to the protected route or layout instead of gating its checks with literal pathname-prefix comparisons such as `url.pathname.startsWith("/admin")`. Literal checks may miss potential URL encodings that React Router route matching would cover.</docs-warning>
479
+
477
480
  ```tsx filename=app/middleware/auth.ts
478
481
  import { redirect } from "react-router";
479
482
  import { userContext } from "~/context";
@@ -635,6 +638,7 @@ export async function loader({
635
638
  [server-client]: #server-vs-client-middleware
636
639
  [framework-action]: ../start/framework/route-module#action
637
640
  [framework-loader]: ../start/framework/route-module#loader
641
+ [getloadcontext]: ../api/other-api/adapter#react-routerexpress
638
642
  [datastrategy]: ../api/data-routers/createBrowserRouter#optsdatastrategy
639
643
  [cms-redirect]: #cms-redirect-on-404
640
644
  [createContext]: ../api/utils/createContext
@@ -6,9 +6,6 @@ title: Navigation Blocking
6
6
 
7
7
  [MODES: framework, data]
8
8
 
9
- <br/>
10
- <br/>
11
-
12
9
  When users are in the middle of a workflow, like filling out an important form, you may want to prevent them from navigating away from the page.
13
10
 
14
11
  This example will show:
@@ -6,9 +6,6 @@ title: Revalidation Optimization
6
6
 
7
7
  [MODES: framework, data]
8
8
 
9
- <br/>
10
- <br/>
11
-
12
9
  After a mutation or some navigations, React Router re-runs loaders so
13
10
  the UI stays in sync with the server. That default is the right
14
11
  starting point. When a loader is expensive, or a mutation cannot
@@ -25,10 +22,10 @@ Prefer targeting a specific action or navigation, and fall back to
25
22
  The default behavior differs between Framework and Data Modes:
26
23
 
27
24
  - **Framework Mode with SSR**
28
- - Defaults to opt-out behavior - active loaders are revalidated on navigations and successful submissions ([`Link`][link], [`Form`][form], [`fetcher.submit`](fetcher-submit))
25
+ - Defaults to opt-out behavior - active loaders are revalidated on navigations and successful submissions ([`Link`][link], [`Form`][form], [`fetcher.submit`][use-fetcher])
29
26
  - Failed submissions returning a 4xx/5xx status do not trigger revalidations by default
30
27
  - **Framework "SPA Mode" and Data Mode**
31
- - Defaults to opt-out behavior on successful submissions - active loaders are revalidated on successful submissions ([`Form`][form], [`fetcher.submit`])
28
+ - Defaults to opt-out behavior on successful submissions - active loaders are revalidated on successful submissions ([`Form`][form], [`fetcher.submit`][use-fetcher])
32
29
  - Failed submissions returning a 4xx/5xx status do not trigger revalidations by default
33
30
  - Defaults to opt-in behavior for GET navigations ([`Link`][link]) - active loaders are only revalidated if their dynamic params changed, or if any search params changed
34
31
  - A GET navigation to the _exact_ same URL is treated like a page refresh and all loaders are revalidated.
@@ -6,9 +6,6 @@ title: Pre-Rendering
6
6
 
7
7
  [MODES: framework]
8
8
 
9
- <br/>
10
- <br/>
11
-
12
9
  Pre-Rendering allows you to speed up page loads for static content by rendering pages at build time instead of at runtime.
13
10
 
14
11
  ## Configuration
@@ -84,10 +81,11 @@ export default {
84
81
 
85
82
  ## Pre-Rendering with/without a Runtime Server
86
83
 
87
- Pre-Rendering can be used in two ways based on the `ssr` config value:
84
+ Pre-Rendering can be used with these `ssr` config values:
88
85
 
89
86
  - Alongside a runtime SSR server with `ssr:true` (the default value)
90
87
  - Deployed to a static file server with `ssr:false`
88
+ - Alongside a runtime API server with `ssr:"unstable_api-only"` (experimental)
91
89
 
92
90
  ### Pre-rendering with `ssr:true`
93
91
 
@@ -223,3 +221,24 @@ When pre-rendering with `ssr:false`, React Router will error at build time if yo
223
221
  - If you are using a `loader` on a pre-rendered route that has child routes, you will need to make sure the parent `loaderData` can be determined at run-time properly by either:
224
222
  - Pre-rendering all child routes so that the parent `loader` can be called at build-time for each child route path and rendered into a `.data` file, or
225
223
  - Use a `clientLoader` on the parent that can be called at run-time for non-pre-rendered child paths
224
+
225
+ ### Pre-rendering with API-only Mode (unstable)
226
+
227
+ <docs-warning>API-only Mode is experimental and may change in minor or patch releases. It is not supported in RSC Framework Mode.</docs-warning>
228
+
229
+ Use `ssr: "unstable_api-only"` with `prerender` to generate documents at build time while keeping a runtime server for loaders, actions, and route discovery:
230
+
231
+ ```ts filename=react-router.config.ts
232
+ import type { Config } from "@react-router/dev/config";
233
+
234
+ export default {
235
+ ssr: "unstable_api-only",
236
+ prerender: ["/"],
237
+ } satisfies Config;
238
+ ```
239
+
240
+ Document generation follows the same behavior as `ssr:false`: selected paths produce HTML and `.data` files, and other paths use a SPA fallback. The fallback is `__spa-fallback.html` when `/` is prerendered, or `index.html` otherwise.
241
+
242
+ Prerendered pages hydrate using their build-time data. Pages using the fallback fetch server loader data during initialization. Server loaders and actions are available on all routes, including those outside the prerender list, and normal loader revalidation remains enabled.
243
+
244
+ See [API-only Mode](../start/framework/rendering#api-only-mode-unstable) for deployment routing and configuring a separate API origin.
@@ -6,9 +6,6 @@ title: Presets
6
6
 
7
7
  [MODES: framework]
8
8
 
9
- <br/>
10
- <br/>
11
-
12
9
  The [React Router config][react-router-config] supports a `presets` option to ease integration with other tools and hosting providers.
13
10
 
14
11
  [Presets][preset-type] can only do two things:
@@ -7,9 +7,6 @@ unstable: true
7
7
 
8
8
  [MODES: framework, data]
9
9
 
10
- <br/>
11
- <br/>
12
-
13
10
  <docs-warning>React Server Components support is experimental and subject to breaking changes in
14
11
  minor/patch releases. Please use with caution and pay **very** close attention
15
12
  to release notes for relevant changes.</docs-warning>
@@ -6,9 +6,6 @@ title: Resource Routes
6
6
 
7
7
  [MODES: framework, data]
8
8
 
9
- <br/>
10
- <br/>
11
-
12
9
  When server rendering, routes can serve "resources" instead of rendering components, like images, PDFs, JSON payloads, webhooks, etc.
13
10
 
14
11
  ## Defining a Resource Route
@@ -0,0 +1,147 @@
1
+ ---
2
+ title: Route Discovery
3
+ unstable: true
4
+ ---
5
+
6
+ # Route Discovery
7
+
8
+ [MODES: framework]
9
+
10
+ <docs-warning>This API is unstable and may change without a major release. It supports conventional Framework Mode; RSC modes are not supported.</docs-warning>
11
+
12
+ Enable the future flag in `react-router.config.ts`:
13
+
14
+ ```ts
15
+ import type { Config } from "@react-router/dev/config";
16
+
17
+ export default {
18
+ future: { unstable_customRouteDiscovery: true },
19
+ } satisfies Config;
20
+ ```
21
+
22
+ Without this flag, React Router keeps its existing discovery implementation and the hook is unavailable. The flag supports conventional Framework Mode only.
23
+
24
+ Enabling the flag does not require a custom implementation or a call to `unstable_useRouteDiscovery`. React Router continues to discover routes automatically and uses its built-in manifest-mismatch recovery unless you provide a custom `onManifestMismatch` handler.
25
+
26
+ Keep `routeDiscovery.mode: "lazy"` (the default for SSR) and use `unstable_useRouteDiscovery` to choose when to discover destinations or load the complete route manifest.
27
+
28
+ ```tsx
29
+ let { state, discoverRoutes, loadAllRoutes } =
30
+ unstable_useRouteDiscovery({
31
+ onManifestMismatch: async (event) => {
32
+ // Handle mismatch, potentially by loading the entire manifest
33
+ await loadAllRoutes();
34
+ },
35
+ });
36
+
37
+ // state: "partial" | "loading" | "complete"
38
+
39
+ // Eagerly discover specific paths
40
+ let result = await discoverRoutes(paths);
41
+ ```
42
+
43
+ ## Imperative Route Discovery
44
+
45
+ You can control route discovery through `discoverRoutes()` without having to render links/forms on the page - this allows you to eagerly discover routes that are not directly linked from the current UI. Note that discovery only loads route metadata - it does not navigate, run loaders/actions, or prefetch route modules/stylesheets. Paths are batched within the manifest request URL limit and previously discovered paths are skipped.
46
+
47
+ `discoverRoutes(paths, { signal })` accepts application-root paths beginning with `/`. React Router applies the configured `basename` and ignores query strings and hashes. Relative paths and external URLs are not supported.
48
+
49
+ The result is `{ type: "success" }`, `{ type: "version-mismatch" }`, or `{ type: "aborted" }`. Success means the discovery operation completed successfully; it does not guarantee that a request was sent or that each pathname matches a route. Cached paths need no request, and a concurrent full-manifest load can supersede an incremental request failure. Unrecovered request failures and unrelated handler errors reject. Imperative mismatches do not automatically trigger a reload.
50
+
51
+ For example, the cart's checkout link automatically discovers the shipping route. Use the hook to discover later checkout steps when the cart mounts, even though those steps aren't linked from the cart:
52
+
53
+ ```tsx
54
+ import { useEffect } from "react";
55
+ import {
56
+ Link,
57
+ unstable_useRouteDiscovery,
58
+ } from "react-router";
59
+
60
+ function Cart() {
61
+ let { discoverRoutes } = unstable_useRouteDiscovery();
62
+
63
+ useEffect(() => {
64
+ let controller = new AbortController();
65
+
66
+ discoverRoutes(
67
+ ["/checkout/billing", "/checkout/review"],
68
+ { signal: controller.signal },
69
+ ).catch(console.error);
70
+
71
+ return () => controller.abort();
72
+ }, [discoverRoutes]);
73
+
74
+ return (
75
+ <>
76
+ {/* Render cart items and totals here. */}
77
+ <Link to="/checkout/shipping">
78
+ Proceed to checkout
79
+ </Link>
80
+ </>
81
+ );
82
+ }
83
+ ```
84
+
85
+ ## Completing discovery
86
+
87
+ `loadAllRoutes()` loads the running client's versioned manifest asset to complete its route tree, even if that client is stale. This merges all missing routes into the running router and thus prevents further incremental discovery. The exposed `version` remains the version of the running client. With `routeDiscovery.mode: "initial"`, SPA Mode, or development's full manifest, the state is already `complete` and the operations are successful no-ops.
88
+
89
+ The shared `state` moves from `partial` to `loading` to `complete`. Concurrent calls share a load, and calls after completion resolve immediately. Failures reject and return the state to `partial`; applications can catch the error and choose whether to reload.
90
+
91
+ Retain the client's versioned manifest **and its referenced assets** for as long as that client is supported. Server routing and loader/action contracts must also remain compatible. Loading build A's manifest does not make an incompatible build B backend safe for build A's client.
92
+
93
+ ## Handling manifest mismatches
94
+
95
+ You can provide custom handling for manifest version mismatches to avoid hard reloads, giving you a chance to complete the route tree, or cancel the navigation and provide a prompt for the user to reload (see below). A mismatch indicates different versions, not which version is newer.
96
+
97
+ ```tsx
98
+ unstable_useRouteDiscovery({
99
+ onManifestMismatch: async (event) => {
100
+ await event.loadAllRoutes();
101
+ },
102
+ });
103
+ ```
104
+
105
+ After mismatch handlers settle, surviving operations continue only if the tree is complete. Otherwise navigations and fetchers are canceled and their pending state settles. Canceling a navigation also cancels any pending revalidation - both return to idle and the current page and data remain in place without another loader pass. Similarly, interrupted fetcher loads settle with their existing data. If an action already changed server data, the displayed data may remain stale until a later navigation or explicit revalidation.
106
+
107
+ Router-managed Back/Forward cancellations restore the prior history position. Additional browser Back/Forward presses during restoration can leave the URL and rendered route out of sync or navigate to another entry; preserving the current screen is not guaranteed in that case.
108
+
109
+ Full-manifest load failures remain catchable and do not render route error boundaries, whether the handler calls `event.loadAllRoutes()` or the function returned by the hook. Uncaught full-load failures are reported through `<HydratedRouter onError>` or `console.error`, and the incomplete operation is canceled. Unrelated handler errors follow normal discovery error handling.
110
+
111
+ ## Temporary overrides
112
+
113
+ Custom mismatch handlers override built-in recovery. Calling the hook without a handler does not override anything. Removing the last custom mismatch handler restores automatic recovery.
114
+
115
+ Call `event.defaultBehavior()` to explicitly run built-in recovery: eager mismatches warn, navigation mismatches reload the destination, fetcher mismatches reload the current document, and imperative mismatches return without reloading. Repeated calls for one shared mismatch event reuse the same promise. It does not invoke other custom handlers or stop their propagation.
116
+
117
+ ```tsx
118
+ unstable_useRouteDiscovery({
119
+ async onManifestMismatch(event) {
120
+ if (hasUnsavedChanges) {
121
+ event.stopPropagation();
122
+ setShowReloadDialog(true);
123
+ return;
124
+ }
125
+ await event.defaultBehavior();
126
+ },
127
+ });
128
+ ```
129
+
130
+ Custom handlers run in reverse registration order, with each awaited before the next. `stopPropagation()` prevents earlier handlers from running; it does not complete discovery or allow an operation to continue against an incomplete tree.
131
+
132
+ ```tsx
133
+ unstable_useRouteDiscovery({
134
+ onManifestMismatch(event) {
135
+ if (hasUnsavedChanges) {
136
+ event.stopPropagation();
137
+ setShowReloadDialog(true);
138
+ }
139
+ },
140
+ });
141
+ ```
142
+
143
+ An editor mounted after a root recovery handler can use this to preserve a draft. Unmounting removes its registration and reveals earlier handlers. Callback updates preserve registration priority. This is registration order, not a guarantee that the deepest component runs first.
144
+
145
+ Eager discovery waits for the initialized route tree to commit so a root handler can intercept the first request. It does not wait for every suspended descendant or guarantee an idle main thread. Discovery needed before handlers can mount retains normal lazy behavior.
146
+
147
+ Without mismatch handlers, existing automatic recovery for eager/navigation/fetcher discovery remains unchanged. Deployment polling and staleness policy remain application-owned.
@@ -6,9 +6,6 @@ title: Route Module Type Safety
6
6
 
7
7
  [MODES: framework]
8
8
 
9
- <br/>
10
- <br/>
11
-
12
9
  React Router generates route-specific types to power type inference for URL params, loader data, and more.
13
10
  This guide will help you set it up if you didn't start with a template.
14
11
 
@@ -6,9 +6,6 @@ title: Security
6
6
 
7
7
  [MODES: framework, data]
8
8
 
9
- <br/>
10
- <br/>
11
-
12
9
  This is by no means a comprehensive guide, but React Router provides features to help address a few aspects under the _very large_ umbrella that is _Security_.
13
10
 
14
11
  ## `Content-Security-Policy`
@@ -6,9 +6,6 @@ title: Server Bundles
6
6
 
7
7
  [MODES: framework]
8
8
 
9
- <br/>
10
- <br/>
11
-
12
9
  <docs-warning>This is an advanced feature designed for hosting provider integrations. When compiling your app into multiple server bundles, there will need to be a custom routing layer in front of your app directing requests to the correct bundle.</docs-warning>
13
10
 
14
11
  React Router typically builds your server code into a single bundle that exports a request handler function. However, there are scenarios where you might want to split your route tree into multiple server bundles, each exposing a request handler function for a subset of routes. To provide this flexibility, [`react-router.config.ts`][react-router-config] supports a `serverBundles` option, which is a function for assigning routes to different server bundles.
@@ -6,9 +6,6 @@ title: Single Page App (SPA)
6
6
 
7
7
  [MODES: framework]
8
8
 
9
- <br/>
10
- <br/>
11
-
12
9
  <docs-info>This guide focuses on how to build Single Page Apps with React Router Framework mode. If you're using React Router in declarative or data mode, you can design your own SPA architecture.</docs-info>
13
10
 
14
11
  When using React Router as a framework, you can enable "SPA Mode" by setting `ssr:false` in your `react-router.config.ts` file. This will disable runtime server rendering and generate an `index.html` at build time that you can serve and hydrate as a SPA.
@@ -22,6 +19,8 @@ Typical Single Page apps send a mostly blank `index.html` template with little m
22
19
 
23
20
  <docs-info>SPA Mode is a special form of "Pre-Rendering" that allows you to serve all paths in your application from the same HTML file. Please refer to the [Pre-Rendering](./pre-rendering) guide if you want to do more extensive pre-rendering.</docs-info>
24
21
 
22
+ <docs-info>If you want a SPA frontend backed by React Router server loaders and actions, see experimental [API-only Mode](../start/framework/rendering#api-only-mode-unstable).</docs-info>
23
+
25
24
  ## 1. Disable Runtime Server Rendering
26
25
 
27
26
  Server rendering is enabled by default. Set the `ssr` flag to `false` in `react-router.config.ts` to disable it.
@@ -6,9 +6,6 @@ title: Status Codes
6
6
 
7
7
  [MODES: framework ,data]
8
8
 
9
- <br/>
10
- <br/>
11
-
12
9
  Set status codes from loaders and actions with `data`.
13
10
 
14
11
  ```tsx filename=app/project.tsx lines=[3,12-15,20,23]
@@ -6,9 +6,6 @@ title: Streaming with Suspense
6
6
 
7
7
  [MODES: framework, data]
8
8
 
9
- <br/>
10
- <br/>
11
-
12
9
  Streaming with React Suspense allows apps to speed up initial renders by deferring non-critical data and unblocking UI rendering.
13
10
 
14
11
  React Router supports React Suspense by returning promises from loaders and actions.
@@ -66,9 +63,28 @@ export default function MyComponent({
66
63
  }
67
64
  ```
68
65
 
69
- ## With React 19
66
+ ## Opt into React's `use()` API
67
+
68
+ <docs-warning>The `unstable_promise` prop is experimental and may change in minor or patch releases.</docs-warning>
69
+
70
+ Use `<Await unstable_promise>` instead of `<Await resolve>` to opt into `React.use` under the hood while keeping the Await API:
71
+
72
+ ```tsx
73
+ <React.Suspense fallback={<div>Loading...</div>}>
74
+ <Await
75
+ unstable_promise={nonCriticalData}
76
+ errorElement={<LoadingError />}
77
+ >
78
+ {(value) => <h3>Non critical value: {value}</h3>}
79
+ </Await>
80
+ </React.Suspense>
81
+ ```
82
+
83
+ This should largely behave the same as `<Await resolve>` while avoiding the legacy React Router promise tracking. Both support render-prop children, `useAsyncValue`, and `useAsyncError`. One notable difference with `unstable_promise` is that `errorElement` only handles promise rejections. Errors thrown while rendering children bubble to the nearest React error boundary.
84
+
85
+ ## Use React directly
70
86
 
71
- If you're using React 19, you can use `React.use` instead of `Await`, but you'll need to create a new component and pass the promise down to trigger the suspense fallback.
87
+ You can also read the promise directly with `React.use`. Pass it to a child component rendered inside `<React.Suspense>` so the boundary can display its fallback while the promise is pending.
72
88
 
73
89
  ```tsx
74
90
  <React.Suspense fallback={<div>Loading...</div>}>
@@ -94,7 +110,7 @@ export const streamTimeout = 10_000;
94
110
 
95
111
  ## Handling early rejections (Node)
96
112
 
97
- React Router waits for all loaders to settle (via `Promise.all`) before it begins streaming the response. Once streaming has started, React Router catches subsequent rejections of your streamed promises and surfaces them to your `<Await>` (or React 19 `React.use`) error UI.
113
+ React Router waits for all loaders to settle (via `Promise.all`) before it begins streaming the response. Once streaming has started, React Router catches subsequent rejections of your streamed promises and surfaces them to your `<Await>` (or `React.use`) error UI.
98
114
 
99
115
  However, if a streamed promise rejects _before_ all of the route's loaders have settled, React Router has not yet been able to attach a handler to it. In Node, an unhandled promise rejection will crash the process unless you have a top-level handler registered.
100
116
 
@@ -6,9 +6,6 @@ title: Using handle
6
6
 
7
7
  [MODES: framework]
8
8
 
9
- <br/>
10
- <br/>
11
-
12
9
  You can build dynamic UI elements like breadcrumbs based on your route hierarchy using the [`useMatches`][use-matches] hook and [`handle`][handle] route exports.
13
10
 
14
11
  ## Understanding the Basics