🏎️ Vite plugin that unblocks Remix v3 apps to be developed, optimized and deployed everywhere with Nitro.
Vite plugin that lets Remix v3 apps be developed, optimized, and deployed everywhere with Nitro.
Remix v3 is cool, but it’s runtime-only — every dependency ships to production unoptimized. Bundles balloon, cold starts drag, and cross-platform deployment becomes nearly impossible.
remix@3.0.0-beta.0 pulls in 112 dependencies from 63 maintainers (npm graph) and requires an on-demand build on server startup using tsx.
Pairing Remix with Vite and Nitro unlocks the build-time optimizations and deployment targets that were previously out of reach.
| metric | buildless (tsx) | build (vite + nitro) | smaller |
|---|---|---|---|
| ship size | 163.33 MB | 295.90 KB | 565× |
| ship size (gzip) | 58.29 MB | 92.04 KB | 649× |
| files | 2,891 | 25 | 116× |
| build time | — | 376 ms | — |
| startup time | 389 ms | 59 ms | 6.6× |
| RSS at ready | 155.01 MB | 96.25 MB | 1.6× |
Benchmarks: source ran on Linux with Node.js v24.15.0 and are only an indicator.
Two plugins, one job each:
vite-plugin-remix3 tells Vite about your app’s two entry graphs — client (your app/entry.client.* files, bundled and hashed) and ssr (your server entry).nitro/vite manages the server. In dev it serves requests through the SSR entry; in prod it produces a .output/ bundle that deploys to Node or anywhere else.?assets=client imports are how SSR finds the right URLs for your client bundle. In components that render <script> / <link> tags:
import entryAssets from "../entry.client.ts?assets=client";
// entryAssets.entry → "/app/entry.client.ts" in dev
// entryAssets.entry → "/assets/app/entry.client-<hash>.js" in prod
In dev these resolve to source URLs that Vite transforms on the fly. In prod they resolve to hashed chunks served as static files from .output/public/. This replaces Remix’s runtime createAssetServer with build-time URLs. Thanks to vite-plugin-fullstack that is enabled out of the box in Nitro!
Quickly start with the starter template:
npx -y giget gh:pi0/vite-plugin-remix3/starter remix3-app
Nitro deployment is zero config and without any additional dependencies!
By default a portable Node.js server will be generated in .output/ dir and you can just run or deploy your app anywhere you want (read the docs)
Example deployments of starter template:
To migrate a stock Remix v3 starter onto Vite + Nitro:
1. Install and add vite.config.ts:
pnpm add -D vite nitro vite-plugin-remix3
// vite.config.ts
import { defineConfig } from "vite";
import { nitro } from "nitro/vite";
import { remix } from "vite-plugin-remix3";
export default defineConfig({ plugins: [nitro(), remix()] });
Update package.json scripts to vite dev / vite build / vite preview, and drop tsx.
2. Delete server.ts and app/assets.ts. Nitro provides the server; Vite replaces the runtime asset server. Also remove the routes.assets handler from app/router.ts (the route entry itself can stay).
3. Create app/entry.server.ts — the default ssrEntry. Nitro reads the SSR handler from its default export:
import { router } from "./router.ts";
export default { fetch: router.fetch };
4. Move app/assets/entry.ts → app/entry.client.ts and switch dynamic import() to import.meta.glob (Vite needs a static module map):
const modules = import.meta.glob([
"/app/**/*.{ts,tsx,js,jsx}",
"!/app/**/*.server.*",
"!/app/**/*.d.ts",
]);
run({
async loadModule(moduleUrl, exportName) {
const key = moduleUrl.replace(/^\/assets/, "");
const mod = await modules[key]();
return mod[exportName];
},
// resolveFrame unchanged
});
5. Use the ?assets=client import in components that emit the entry <script> (e.g. document.tsx), so prod gets the hashed URL:
import entryAssets from "../entry.client.ts?assets=client";
{
entryAssets.css.map((f) => <link rel="stylesheet" href={f.href} />);
}
<script type="module" src={entryAssets.entry} />;
6. Add .output to .gitignore.
[!IMPORTANT]
Don’t reintroduce a top-levelserver.tsimporting app/router.ts — it pulls the rendering chain into Nitro’s build graph and the asset manifest comes out empty. See AGENTS.md.
Published under the MIT license 💛.