One app. One deploy. Full type safety from database to DOM.
0.4: NestJS 11 and 12, per-page code loading, view edits without restarts.
Controller return type is the component's props. Change one, the other breaks at build time.
Nested layouts persist across navigations. Header, sidebar, shell — rendered once, never re-mounted.
renderToString for simplicity, renderToPipeableStream for performance. Suspense boundaries stream as they resolve.
Link clicks fetch only the changed segment. The rest of the page stays alive — state, scroll, animations.
The standard approach to SSR with a backend framework: build the API, then build a separate frontend app that calls it. Whether it's Next.js, TanStack Start, Remix, or a plain Vite SPA — you end up with two routers, two deploys, and a type boundary you maintain by hand.
This library takes a different approach. React lives inside your NestJS app as a view layer. Controllers return data, components render it, TypeScript enforces the contract. One process, one build, one deploy.
The controller declares what data to return and which component renders it. The component receives typed props. TypeScript connects them.
import { Controller, Get, Param } from '@nestjs/common';
import { Render, Layout } from '@nestjs-ssr/react';
import { RecipesLayout } from './views/recipes-layout';
import { RecipeDetail } from './views/recipe-detail';
@Controller('recipes')
@Layout(RecipesLayout)
export class RecipesController {
@Get(':slug')
@Render(RecipeDetail)
getRecipe(@Param('slug') slug: string) {
const recipe = this.recipes.findBySlug(slug);
return {
recipe,
chef: this.chefs.findById(recipe.chefId),
head: { title: recipe.name },
};
}
}import { PageProps } from '@nestjs-ssr/react';
export default function RecipeDetail({
recipe,
chef,
}: PageProps<RecipeDetailProps>) {
return (
<article>
<h1>{recipe.name}</h1>
<p>{recipe.description}</p>
<IngredientList items={recipe.ingredients} />
<ChefCard chef={chef} />
</article>
);
}Return the wrong shape and TypeScript catches it before the code runs.
nestjs-ssr dev restarts Nest only when a controller or service changes; view edits go through Vite, and the next server render already has them.One command. NestJS 11 or 12, Express or Fastify.
npx @nestjs-ssr/react init