React Router v8
This guide starts with an existing React Router v8 framework-mode app.
Use a shared build directory
Set an explicit build directory in your React Router config:
React Router will place browser assets in build/client. Nitro will place the runnable server in build/server.
Create the React Router server handler
Create server/ssr.ts:
This adapts React Router's generated server build to the Fetch API handler Nitro expects.
Configure Vite
Update vite.config.ts:
Keep dirs: ["workflows"] so subsequent builds do not scan generated files under build. Place reactRouter() before nitro() in the plugin array.
Create a workflow
Create workflows/greeting.ts:
Start the workflow from a Nitro route
Create server/routes/api/greeting.post.ts:
React Router continues to handle your application routes. Nitro handles this server route at POST /api/greeting, as well as Workflow SDK's internal routes.
Run the app
Start the development server:
Then start a workflow:
Build and start the production server:
You can inspect local runs with pnpm workflow web.
Troubleshooting
React Router pages return 404
Check that the ssr environment input points to ./server/ssr.ts.
A second build tries to compile files under build/server
Use workflow({ dirs: ["workflows"] }), remove the existing build directory once, and rebuild.
vite build finishes output but does not exit
Use workflow@5.0.0 or later with Nitro v3.