React Router
Prisma.Website.ReactRouter builds React Router
v7 in framework mode through your project’s Vite pipeline. The shared
Node target wraps the server manifest with createRequestHandler and
serves client assets first. The output runs on Bun in Prisma Compute
from a tar.gz upload, without a Docker image or registry.
Install
Section titled “Install”Install the build-time integration; the resource loads /react-router
and /react-router/node from your project:
bun add -d @alchemy.run/frontend-frameworks @vercel/nftnpm install -D @alchemy.run/frontend-frameworks @vercel/nftpnpm add -D @alchemy.run/frontend-frameworks @vercel/nftyarn add -D @alchemy.run/frontend-frameworks @vercel/nftKeep the framework scaffold’s react-router, @react-router/dev,
@react-router/node, isbot, and vite. Put @react-router/node and
isbot in dependencies: React Router reads them when choosing its
default server entry and may try to install isbot if it is missing.
Configure Vite
Section titled “Configure Vite”Keep the ordinary framework plugin and your Vite plugins:
import { reactRouter } from "@react-router/dev/vite";import tailwindcss from "@tailwindcss/vite";import { defineConfig } from "vite";
export default defineConfig({ plugins: [tailwindcss(), reactRouter()],});No deployment adapter or server preset is needed.
Declare the Website
Section titled “Declare the Website”import * as Prisma from "alchemy/Prisma";
export const Website = Prisma.Website.ReactRouter("Website", { rootDir: "./web",});rootDir holds package.json, vite.config.*, and
react-router.config.ts; omit it for .. Live deploy creates a
database-less project unless you pass project.
Add it to the Stack
Section titled “Add it to the Stack”import * as Alchemy from "alchemy";import * as Effect from "effect/Effect";
export default Alchemy.Stack( "MyReactRouterSite", { providers: Prisma.providers(), state: Alchemy.localState() }, Effect.gen(function* () { const site = yield* Website; return { url: site.url }; }),);site.url is the Compute endpoint on deploy. Requests that miss client
assets go to SSR routes, loaders, actions, and resource routes on Bun.
How the two build outputs are deployed
Section titled “How the two build outputs are deployed”Both build/client and build/server go into the uploaded artifact.
The client directory contains browser bundles and public/ files.
build/server/index.js is a manifest, so Alchemy wraps it with React
Router’s request handler rather than executing it as a standalone server.
A custom buildDirectory is read from the resolved config. If you set
Vite’s base, give React Router’s basename the same prefix so emitted
asset paths match the deployed files.
Add environment variables
Section titled “Add environment variables”export const Website = Prisma.Website.ReactRouter("Website", { rootDir: "./web", env: { API_BASE: "https://api.example.com" },});Values are applied before build and dev and passed to Compute. VITE_*
keys are inlined into browser code; keep secrets out of those keys.
Outputs from sibling resources can be passed in env when declaring
the Website inside your Stack generator.
Read the environment in a loader
Section titled “Read the environment in a loader”export function loader() { return { apiBase: process.env.API_BASE ?? "unset" };}Loaders and actions run on Bun and read process.env.
Read the environment in a resource route
Section titled “Read the environment in a resource route”export function loader() { return new Response(process.env.API_BASE ?? "unset");}A route module without a default component is a resource route. It uses the same runtime environment.
Local dev
Section titled “Local dev”bun alchemy dev runs React Router’s Vite dev server with HMR; the
Website creates no Prisma resources. Opt into live deployment during dev:
export const Website = Prisma.Website.ReactRouter("Website").pipe( Alchemy.remote(),);Custom domain
Section titled “Custom domain”const site = yield* Prisma.Website.ReactRouter("Web", { domain: "app.example.com",});Prisma.CustomDomain requires the app to be on the current default
branch. Configure returned DNS records yourself and verify status before
cutover; see Custom domains.