React Router on Easel
Deploy full-stack React Router 7 and 8 applications to Easel with server rendering, streaming, loaders, actions, middleware, static prerendering, and SPA support.
At a glance
| Support level | Production-ready |
| Supported versions | React Router 7 and 8 |
| Mode | Framework Mode |
| Rendering | Static, SPA, SSR, streaming, and prerendering |
| Server runtime | Node.js |
| Required preset | @vercel/react-router |
| Automatic detection | Yes |
| Most recently tested with | React Router 8.3.x and 7.18.x |
React Router 8 is a non-breaking framework upgrade from React Router 7, but it raises the minimum versions of Node.js, React, and Vite. Existing React Router 7 applications can deploy without upgrading.
Version requirements
React Router 8
React Router 8 requires:
- Node.js 22.22.0 or newer
- React 19.2.7 or newer
- Vite 7 or newer
- An ESM project
React Router 8 enables the behaviors previously introduced through React Router 7’s future.v8_* flags by default.
React Router 7
React Router 7 supports older Node.js, React, and Vite baselines. Some newer framework behaviors, including stable middleware behavior, require future flags depending on the version you use.
For the most consistent migration path to React Router 8, enable the available future.v8_* flags and resolve any compatibility issues before upgrading.
Deploy a React Router application
Easel supports React Router applications using Framework Mode.
Install the deployment preset:
Add the preset to react-router.config.ts:
Then create a project and connect the project’s Git repository, or deploy with the CLI:
Easel detects the React Router project, runs its production build, and provisions the static and server resources described by the generated deployment output.
You can override the install command, build command, root directory, Node.js version, and environment variables in your project settings.
Why run React Router on Easel?
Easel provides a Vercel-compatible React Router deployment path with visible infrastructure, portable application conventions, and integrated edge services.
A React Router deployment includes:
- Immutable browser assets served through the Easel CDN
- Regional functions for server rendering, loaders, and actions
- Streaming HTTP responses
- Route-aware server bundles
- CDN caching controlled through standard response headers
- Preview deployments for branches and pull requests
- Built-in logs, metrics, traces, WAF, and attack protection
You can inspect deployed functions, request execution, cache behavior, and resource usage from the Easel dashboard.
What Easel deploys
The React Router preset exposes the application’s route structure and generates the deployment output Easel consumes.
| React Router output | Easel resource |
|---|---|
| Browser JavaScript and CSS | CDN assets |
| Public files | CDN assets |
| Prerendered pages | CDN assets |
| Server-rendered routes | Easel Functions |
| Loaders and actions | Easel Functions |
| Resource routes | Easel Functions |
| Server middleware | Application function pipeline |
| Streaming responses | Streaming function responses |
| SPA fallback | CDN routing configuration |
The preset allows server bundles to be split according to the application’s route structure rather than placing the entire server application in one undifferentiated function bundle.
Function CPU, memory, and duration remain controlled by Easel project settings
and framework route metadata (such as maxDuration). Functions run in US East.
Supported features
| Feature | Support | Notes |
|---|---|---|
| Framework Mode | Supported | Uses the React Router Vite plugin |
| React Router 8 | Supported | Requires the React Router 8 runtime baseline |
| React Router 7 | Supported | Future flags may be required for newer behavior |
| Server-side rendering | Supported | Dynamic document requests run in Easel Functions |
| Client-side navigation | Supported | Data requests are handled by the application function |
| Loaders | Supported | Run during document and applicable client-navigation requests |
| Actions | Supported | Handles mutations and form submissions |
| Nested routes | Supported | Includes nested layouts and data loading |
| Route error boundaries | Supported | Framework error responses are preserved |
| Streaming | Supported | Includes Suspense and deferred route data |
| Resource routes | Supported | Return JSON, files, feeds, and other non-UI responses |
| Server middleware | Supported | Stable in v8. Version-dependent setup in v7 |
| Client middleware | Supported | Runs in the browser during client navigations |
| Route context | Supported | Includes type-safe RouterContextProvider behavior |
| Static prerendering | Supported | Generated pages deploy to the CDN |
| SPA mode | Supported | Deploys a client-rendered application with route fallback |
| HTTP redirects | Supported | Includes redirects returned by loaders, actions, and middleware |
| Response headers | Supported | Includes route headers exports |
| Cookie sessions | Supported | Standard Cookie and Set-Cookie headers are preserved |
| File uploads | Supported | Subject to function request and duration limits |
| OpenTelemetry | Supported | Instrument application server code using standard SDKs |
| Custom server entry | Supported | Must expose the expected Web API request handler |
| WebSockets | Not supported | Function routes use HTTP request-response semantics |
| Persistent local storage | Not supported | Function filesystems are ephemeral |
Server rendering
Server rendering is enabled by default in Framework Mode.
A route can load data on the server and pass it to the component through generated route types:
For an initial document request, Easel invokes the application function and streams the rendered response to the client.
After hydration, React Router can request loader data without rerendering the complete document. Those data requests are routed to the same deployed application runtime.
Actions and forms
React Router actions handle mutations and form submissions:
The browser submits the form to the Easel Function running the React Router server application. Redirects, validation responses, cookies, and error boundaries continue through the framework’s normal response flow.
Streaming
React Router can begin returning a document before all asynchronous data is available.
A loader can return unresolved promises:
Easel forwards response chunks as React Router produces them rather than waiting for the entire render to finish.
The function remains active until the stream closes or the invocation reaches its maximum duration.
Middleware
React Router middleware can run before and after the matched route’s handlers.
Use middleware for authentication, request context, logging, instrumentation, response headers, and session handling.
Server middleware runs inside the deployed React Router application function. It is distinct from Easel’s platform-level edge request pipeline and WAF.
Middleware in React Router 8
Middleware behavior is enabled by default in React Router 8.
No future.v8_middleware flag is required.
Middleware in React Router 7
React Router 7 versions that expose middleware behind a future flag require it in react-router.config.ts:
The exact future flags available depend on the installed React Router 7 release.
Request context
Use React Router’s context APIs to make request-specific dependencies available to middleware, loaders, and actions.
A custom server entry can seed the request context before React Router handles the request:
Use request context for dependencies that belong to one invocation, such as authenticated users, database transaction handles, request identifiers, or platform metadata.
Do not use module-level mutable state as a substitute for request context. A function instance may process multiple requests during its lifetime.
Resource routes
A route that does not export a default component can return a non-HTML response:
Resource routes can return:
- JSON APIs
- XML and RSS feeds
- Generated files
- Redirects
- Streaming responses
- Webhook acknowledgements
They run within the same function execution model as document loaders and actions.
Response caching
React Router does not impose one application caching policy. Routes can control browser and CDN behavior using standard HTTP response headers.
Export a headers function from a route:
In this example:
- Browsers follow the browser caching directives in the response
- Easel’s CDN can reuse the response for 60 seconds
- A stale response can remain available while it is refreshed for up to five minutes
Do not publicly cache responses containing user-specific or session-specific data.
For personalized routes, use:
A route’s caching policy should account for every header, cookie, query parameter, and authentication state that can change its response.
See Cache responses at the edge and Invalidate and revalidate cached content.
Static prerendering
React Router can generate selected routes during the production build.
Configure prerendered paths in react-router.config.ts:
Easel deploys the generated HTML and browser assets to the CDN.
Prerendered routes do not require a function invocation unless the application later navigates to server-backed data or another dynamic route.
React Router 8 uses its Vite environment-based prerendering flow. React Router 7 may use a version-dependent implementation, but the resulting static output is deployed through the same Easel path.
SPA mode
Set ssr to false to deploy a client-rendered single-page application:
Easel deploys the generated browser application to the CDN and routes application paths to its SPA entry document.
In SPA mode:
- Route components run in the browser
- Server loaders and actions are unavailable
clientLoaderandclientActionremain available- Static application assets are served without invoking a function
Use the Vite guide instead when the application uses React Router only in Data Mode or Declarative Mode and does not use the Framework Mode build system.
Route module splitting
React Router can split route-module exports into smaller browser chunks so data and middleware code can load separately from component code.
React Router 8 enables its updated route-module behavior through top-level configuration and defaults inherited from the v8 release.
In compatible React Router 7 versions, the behavior may be enabled through a future flag:
This is primarily a browser-bundle optimization. Easel also uses the route information exposed by the deployment preset when constructing server bundles.
Sessions and cookies
React Router’s cookie and session APIs work through standard HTTP headers.
Cookie-backed sessions do not require server storage, but their contents are sent with each applicable request.
Use a database or durable key-value store for session state that is too large for a cookie, must be revoked centrally, or must be shared with other services.
Environment variables
Configure environment variables in the Easel dashboard or CLI.
Server-side variables are available to loaders, actions, middleware, resource routes, and server entry code:
Do not expose process.env directly to browser code.
When browser code needs public configuration, return an explicit allowlist from the root loader:
Only expose values that are safe for every visitor to read.
Use separate environment values for production, preview, and development deployments when necessary.
OpenTelemetry
React Router server code runs in the Node.js application function and can use standard OpenTelemetry instrumentation.
Initialize instrumentation before handling application requests:
Easel can ingest application telemetry alongside function logs, request metrics, and platform traces.
Avoid starting a new SDK for each request. Initialize reusable instrumentation at module scope and attach request-specific data through spans or context.
Project configuration
Easel detects conventional React Router Framework Mode settings automatically:
| Setting | Default |
|---|---|
| Install command | Detected from the package manager |
| Build command | Package script or react-router build |
| Development command | Package script or react-router dev |
| Static assets | Detected from the framework build |
| Server output | Detected from the deployment preset |
| Node.js version | Project or platform default |
For React Router 8, select a Node.js version compatible with its required baseline.
For monorepos, set the project root to the directory containing:
- The application’s
package.json react-router.config.ts- The Vite configuration
- The application routes
Local development
Continue using React Router’s normal development server:
The framework dev server provides routing, loaders, actions, server rendering, middleware, and hot module replacement.
Use Easel preview deployments to validate platform-specific behavior, including:
- The production server bundle
- Route-aware function packaging
- CDN caching
- Streaming through the production network
- Environment variables
- Function limits (including duration)
- WAF and security rules
A preview deployment follows the same build and deployment path as production and receives an immutable URL.
Upgrading from React Router 7 to 8
React Router 8 is designed as a non-breaking application API upgrade for projects that adopted the v8 future behavior in React Router 7.
Before upgrading:
- Upgrade the application to the latest React Router 7 release
- Enable supported
future.v8_*flags - Resolve deprecations and behavior changes
- Upgrade Node.js to at least 22.22.0
- Upgrade React to at least 19.2.7
- Upgrade Vite to version 7 or newer
- Confirm the project is ESM-compatible
- Upgrade the React Router packages together
- Remove obsolete
future.v8_*flags - Create an Easel preview deployment and test dynamic routes
React Router 8 makes the v8 middleware, request-passthrough, Vite environment, and related future behavior the default.
A typical package upgrade is:
Upgrade any React Router adapters or deployment presets to versions that explicitly support React Router 8.
Known limitations
WebSockets
React Router routes deployed to Easel Functions cannot accept long-lived WebSocket connections.
Use an external WebSocket provider or a dedicated persistent service for bidirectional connections.
Streaming HTTP responses and Server-Sent Events are separate protocols and may be used within the function’s execution limits.
Local filesystem
The function filesystem is ephemeral. Files written during one invocation are not guaranteed to exist during a later invocation or on another function instance.
Use object storage, a database, or another durable service for persistent data.
Long-running work
Loaders, actions, and middleware run within the function’s maximum duration.
Do not rely on untracked work continuing after a response is returned. Use a durable queue or background-job system for work that requires retries, may exceed the function limit, or must survive instance termination.
Custom Node.js servers
Easel deploys the Web API-compatible React Router request handler generated by the framework integration. An application that requires ownership of a persistent HTTP server, raw TCP sockets, or process-level connection handling may require a dedicated service rather than Easel Functions.
Troubleshooting
The build cannot import React Router 8
Confirm that the project uses:
- Node.js 22.22.0 or newer
- React 19.2.7 or newer
- Vite 7 or newer
- ESM-compatible configuration
React Router 8 does not support older runtime baselines.
Middleware does not run in React Router 7
Confirm that the installed React Router 7 release supports middleware and that future.v8_middleware is enabled.
Also remember that a client-side navigation with no server loader or action may not make a server request. Server middleware only runs when the navigation reaches the server.
A loader runs locally but not in production
Confirm that SSR has not been disabled with:
SPA mode does not deploy server loaders or actions.
A route returns stale content
Inspect the route’s Cache-Control header. Do not apply shared CDN caching to authenticated or personalized responses unless the cache key safely distinguishes every response variant.
A cookie is not being set
Confirm that:
- The response includes
Set-Cookie - The cookie’s domain and path match the request
securecookies are tested over HTTPS- The cookie does not exceed browser size limits
- An ancestor middleware does not replace the response headers
Deep links return a 404 in SPA mode
Confirm that the application is built with React Router’s SPA mode rather than as an unrelated static Vite output. The framework deployment output includes the routing fallback Easel needs for application paths.
The application works on React Router 7 but fails after upgrading
Check the React Router 8 runtime baselines first. Then remove obsolete future flags and verify that deployment adapters and Vite plugins support v8.
Run the upgrade through a preview deployment before promoting it to production.
Compatibility policy
Easel tests its React Router integration with representative Framework Mode applications covering:
- React Router 7 and 8
- Server rendering
- Client navigations
- Loaders and actions
- Streaming
- Middleware
- Request context
- Resource routes
- Static prerendering
- SPA mode
- Sessions and cookies
- Response caching
- Route error boundaries
Stable releases may work beyond the versions listed at the top of this page, but those versions are the most recently verified baselines.
For a newly released React Router version, create a preview deployment before upgrading the production application.