A lightweight Fastify plugin for Inertia.js that lets you build modern single-page applications with server-side rendering.
npm install fastify-inertiajsbash
For React
npx degit mahendra7041/fastify-inertia/examples/react my-inertia-app
For Vue
npx degit mahendra7041/fastify-inertia/examples/vue my-inertia-app
For Svelte
npx degit mahendra7041/fastify-inertia/examples/svelte my-inertia-app
cd my-inertia-app
npm install
npm run dev
`
Setup Guide
$3
- Node.js 18 or higher
- Fastify
- Vite
$3
First, create a new project using Vite with your preferred framework:
`bash
For React (used in this guide)
npm create vite@latest my-inertia-app -- --template react
For Vue
npm create vite@latest my-inertia-app -- --template vue
For Svelte
npm create vite@latest my-inertia-app -- --template svelte
cd my-inertia-app
`
$3
Install the necessary dependencies for Fastify and Inertia:
`bash
For React (used in this guide)
npm install fastify-inertiajs @fastify/cookie @fastify/session @fastify/static @inertiajs/react
For Vue
npm install fastify-inertiajs @fastify/cookie @fastify/session @fastify/static @inertiajs/vue3
For Svelte
npm install fastify-inertiajs @fastify/cookie @fastify/session @fastify/static @inertiajs/svelte
Additional dev dependencies
npm install -D nodemon
`
$3
Set up your project structure as follows:
`
my-inertia-app/
├── build/ # Generated build artifacts
├── public/ # Static assets
├── src/
│ ├── pages/ # Inertia page components
│ ├── assets/ # Styles, images, etc.
│ ├── main.jsx # Client entry point (or .js/.vue/.svelte)
│ └── ssr.jsx # SSR entry point (optional)
├── index.html # HTML template
├── vite.config.js # Vite configuration
├── server.js # Express server
└── package.json
`
$3
`html
class="bg-neutral-50 text-black selection:bg-teal-300 dark:bg-neutral-900 dark:text-white dark:selection:bg-pink-500 dark:selection:text-white"
$3
`javascript
import fastify from "fastify";
import fastifyStatic from "@fastify/static";
import fastifyCookie from "@fastify/cookie";
import fastifySession from "@fastify/session";
import inertia from "fastify-inertiajs";
import path from "path";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
async function bootstrap() {
const app = fastify();
const PORT = process.env.PORT || 5000;
// Serve static files in production
if (process.env.NODE_ENV === "production") {
await app.register(fastifyStatic, {
root: path.join(__dirname, "build/client"),
prefix: "/",
decorateReply: false,
});
}
await app.register(fastifyCookie);
await app.register(fastifySession, {
secret:
process.env.SESSION_SECRET ||
"a secret with minimum length of 32 characters",
saveUninitialized: true,
cookie: {
maxAge: 1000 60 60 * 24,
secure: process.env.NODE_ENV === "production",
},
});
await app.register(inertia, {
rootElementId: "root",
assetsVersion: "v1",
ssrEnabled: true,
ssrEntrypoint: "src/ssr.jsx",
ssrBuildEntrypoint: "build/ssr/ssr.js",
});
app.get("/", (req, reply) => {
reply.inertia.render("home");
});
try {
await app.listen({ port: PORT });
console.log(Server is running at http://localhost:${PORT});
} catch (err) {
console.error(err);
process.exit(1);
}
}
bootstrap().catch(console.error);
`
$3
`json
{
"scripts": {
"dev": "nodemon server.js",
"start": "cross-env NODE_ENV=production node server.js",
"build": "npm run build:ssr && npm run build:client",
"build:client": "vite build --outDir build/client",
"build:ssr": "vite build --outDir build/ssr --ssr src/ssr.jsx"
}
}
`
$3
Update your framework's main entry point accordingly. For more details, visit Inertia.js Client-Side Setup:
`javascript
import { createInertiaApp } from "@inertiajs/react";
import { createRoot } from "react-dom/client";
createInertiaApp({
id: "root",
resolve: (name) => {
const pages = import.meta.glob("./pages/*/.jsx", { eager: true });
return pages[./pages/${name}.jsx];
},
setup({ el, App, props }) {
createRoot(el).render( );
},
});
`
$3
Add Server-Side Rendering support for improved SEO and performance.
`javascript
import ReactDOMServer from "react-dom/server";
import { createInertiaApp } from "@inertiajs/react";
export default function render(page) {
return createInertiaApp({
id: "root",
page,
render: ReactDOMServer.renderToString,
resolve: (name) => {
const pages = import.meta.glob("./pages/*/.jsx", { eager: true });
return pages[./pages/${name}.jsx];
},
setup: ({ App, props }) => ,
});
}
`
Configuration
$3
| Option | Type | Default | Description |
| ---------------------- | -------------------- | --------------------------------------------------------- | ------------------------------------------------------------- |
| rootElementId | string? | "app" | DOM element ID where the Inertia app mounts |
| assetsVersion | string? | "v1" | Version string used for inertia |
| encryptHistory | boolean? | true | Encrypts the Inertia history state for security |
| indexEntrypoint | string? | "index.html" | Path to your base HTML template (used in dev mode) |
| indexBuildEntrypoint | string? | "build/client/index.html" | Path to the built client HTML entrypoint (used in production) |
| ssrEnabled | boolean? | false | Enables/disables server-side rendering (SSR) |
| ssrEntrypoint | string? | Required if ssrEnabled: true | Path to your SSR entry file (used in development) |
| ssrBuildEntrypoint | string? | Required if ssrEnabled: true | Path to the built SSR bundle (used in production) |
| vite | ViteResolveConfig? | { server: { middlewareMode: true }, appType: "custom" } | Passes custom options to the Vite dev server |
API Reference
$3
Initializes and returns the Express middleware.
`javascript
await fastify.register(inertia, inertiaConfig);
`
$3
Renders an Inertia page component.
`javascript
fastify.get('/users', (request, reply) => {
const users = await User.findAll();
reply.inertia.render('user/index', {
users: users,
page: req.query.page || 1
});
});
`
$3
Shares data with the current and subsequent requests.
`javascript
reply.inertia.share({
auth: {
user: req.user,
permissions: req.user?.permissions,
},
});
`
$3
Redirects the user to a different location while preserving Inertia’s client-side navigation.
`javascript
fastify.get("/home", (req, reply) => {
// Redirect with default status (302 Found)
reply.inertia.redirect("/dashboard");
// Redirect with explicit status
reply.inertia.redirect(301, "/new-home");
});
`
Contributing
We welcome contributions! Please feel free to submit issues, feature requests, or pull requests.
$3
1. Fork the repository
2. Create your feature branch:
`bash
git checkout -b feat/amazing-feature
`
3. Commit your changes with a descriptive message:
`bash
git commit -m "feat: add amazing feature"
`
4. Push to your branch:
`bash
git push origin feat/amazing-feature
``