Remix/React Router "remix vite:build" Fails - Fix Server Build in CI
Remix (now React Router framework mode) builds a client bundle and a server bundle from the same routes. The build fails most often when a server-only dependency (a database client, fs, a secret-reading module) leaks into the client graph, or a build-time dependency is missing.
What this error means
A remix vite:build / react-router build fails with a resolve error for a Node builtin in the client bundle (Cannot resolve "fs"), or a server module being included client-side. It surfaces at build time, not in remix dev.
Error: The following dependencies are imported but could not be resolved:
fs (imported by app/routes/admin.tsx)
Are they installed?
x Build failed in 1.20sCommon causes
Server-only code imported into a client module
A module using fs/a DB client is imported at the top level of a route that also runs on the client, so the client build tries (and fails) to bundle a Node-only dependency.
Build-time dependency missing
A loader/build dependency is not installed, so a clean npm ci build cannot resolve it.
How to fix it
Isolate server-only modules
Keep server-only code in .server modules (or only inside loader/action) so it never enters the client graph.
// app/db.server.ts - the .server suffix keeps it out of the client bundle
import { Pool } from 'pg'
export const pool = new Pool()
// app/routes/admin.tsx
export async function loader() {
const { pool } = await import('~/db.server')
// ...
}Install missing build dependencies
npm install <missing-dep>
npm ls <missing-dep> # confirm it's a direct dependencyHow to prevent it
- Put server-only code in
.servermodules. - Access DB/fs only inside
loader/action, never at module top level of shared routes. - Run the production build in CI so client/server leaks fail before deploy.