
Security News
Meet Socket at Black Hat Europe and BSides London 2025
Socket is heading to London! Stop by our booth or schedule a meeting to see what we've been working on.
@brendonjohn/react-ssr-nestjs-express
Advanced tools
props
propsHead component for better SEOprocess.env.NODE_ENV !== 'production'Install it:
# install NestJS dependencies
$ npm install --save @nestjs/core @nestjs/common @nestjs/platform-express
# install @react-ssr/nestjs-express
$ npm install --save @react-ssr/core @react-ssr/nestjs-express react react-dom
And add a script to your package.json like this:
{
"scripts": {
"start": "ts-node --project tsconfig.server.json server/main.ts"
}
}
Then, populate files below inside your project:
.babelrc:
{
"presets": [
"@brendonjohn/react-ssr-nestjs-express/babel"
]
}
tsconfig.json:
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"moduleResolution": "node",
"jsx": "preserve",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"strict": true,
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true
},
"exclude": [
"node_modules",
"ssr.config.js",
".ssr"
]
}
tsconfig.server.json:
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "commonjs"
},
"include": [
"server"
]
}
server/main.ts:
import { NestFactory } from '@nestjs/core';
import { NestExpressApplication } from '@nestjs/platform-express';
import register from '@react-ssr/nestjs-express/register';
import { AppModule } from './app.module';
(async () => {
const app = await NestFactory.create<NestExpressApplication>(AppModule);
// register `.tsx` as a view template engine
await register(app);
app.listen(3000, async () => {
console.log(`> Ready on http://localhost:3000`);
});
})();
server/app.module.ts:
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
@Module({
controllers: [
AppController,
],
})
export class AppModule {}
server/app.controller.ts:
import {
Controller,
Get,
Render,
} from '@nestjs/common';
@Controller()
export class AppController {
@Get()
@Render('index') // this will render `views/index.tsx`
public showHome() {
const user = { name: 'NestJS' };
return { user };
}
}
views/index.tsx:
interface IndexProps {
user: any;
}
const Index = ({ user }: IndexProps) => {
return <p>Hello {user.name}!</p>;
};
export default Index;
Finally, just run npm start and go to http://localhost:3000, and you'll see Hello NestJS!.
ssr.config.js)Here is the default ssr.config.js, which is used by react-ssr when there are no valid values:
module.exports = {
id: 'default',
distDir: '.ssr',
viewsDir: 'views',
staticViews: [],
webpack: (config /* webpack.Configuration */, env /* 'development' | 'production' */) => {
return config;
},
};
ssr.config.js#idThe id of UI framework. (default: default)
It can be ignored only when the project does not use any UI frameworks.
Supported UI frameworks are:
default doesn't need to be specified in ssr.config.js)
For example, if we want to use emotion, ssr.config.js is like this:
module.exports = {
id: 'emotion',
};
ssr.config.js#distDirThe place where react-ssr generates production results. (default: .ssr)
If we use TypeScript or any other library which must be compiled, the config below may be useful:
module.exports = {
// dist folder should be ignored by `.gitignore`
distDir: 'dist/.ssr',
};
ssr.config.js#viewsDirThe place where we put views. (default: views)
A function res.render('xxx') will render views/xxx.jsx or views/xxx.tsx.
A working example is here: examples/basic-custom-views
ssr.config.js#staticViewsIf specified, react-ssr generates html cache when production:
module.exports = {
staticViews: [
'auth/login',
'auth/register',
'about',
],
};
ssr.config.js#webpack()module.exports = {
webpack: (config /* webpack.Configuration */, env /* 'development' | 'production' */) => {
// we can override default webpack config here
return config;
},
};
Just put _document.tsx into the views root:
views/_document.tsx:
import React from 'react';
import {
Document,
Head,
Main,
} from '@react-ssr/nestjs-express';
export default class extends Document {
render() {
return (
<html lang="en">
<Head>
<title>Default Title</title>
<meta charSet="utf-8" />
<meta name="viewport" content="minimum-scale=1, initial-scale=1, width=device-width" />
<link rel="shortcut icon" href="/favicon.ico" />
</Head>
<body>
<Main />
</body>
</html>
);
}
};
Note:
<Main /> component directly under <body> tag and don't wrap <Main /> component with another components, because this is a hydration target for the client.And then, use it as always:
views/index.tsx:
const Index = (props) => {
return <p>Hello World!</p>;
};
export default Index;
A working example is here: examples/basic-custom-document
HeadWe can use the Head component in any pages:
views/index.tsx:
import React from 'react';
import { Head } from '@react-ssr/nestjs-express';
const Index = (props) => {
return (
<React.Fragment>
<Head>
<title>Dynamic Title</title>
<meta name="description" content="Dynamic Description" />
</Head>
<p>Of course, SSR Ready!</p>
</React.Fragment>
);
};
export default Index;
A working example is here: examples/basic-dynamic-head
default doesn't need to be specified in ssr.config.js)

Like semantic-ui, non CSS-in-JS frameworks are supported without extra configuration.
All we have to do is to load global CSS in _document or each page:
views/_document.tsx:
import React from 'react';
import {
Document,
Head,
Main,
} from '@react-ssr/express';
export default class extends Document {
render() {
return (
<html>
<Head>
<title>A Sample of Semantic UI React</title>
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.css" />
</Head>
<body>
<Main />
</body>
</html>
);
}
}

In order to enable SSR, we must install babel-plugin-import as devDependencies.
And then, populate .babelrc in your project root:
{
"presets": [
"@brendonjohn/react-ssr-express/babel"
],
"plugins": [
[
"import",
{
"libraryName": "antd",
"style": "css"
}
]
]
}
A working example is here: examples/with-jsx-antd

In order to enable SSR, we must install these packages:
And then, populate .babelrc in your project root:
{
"presets": [
"@brendonjohn/react-ssr-express/babel"
],
"plugins": [
"emotion"
]
}
A working example is here: examples/with-jsx-emotion

We can use material-ui without extra configuration.
A working example is here: examples/with-jsx-material-ui

In order to enable SSR, we must install babel-plugin-styled-components as devDependencies.
And then, populate .babelrc in your project root:
{
"presets": [
"@brendonjohn/react-ssr-express/babel"
],
"plugins": [
"styled-components"
]
}
A working example is here: examples/with-jsx-styled-components
.jsx
.tsx
Introducing an Alternative to NEXT.js
[Express] React as a View Template Engine?
FAQs
React SSR as a view template engine
We found that @brendonjohn/react-ssr-nestjs-express demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Socket is heading to London! Stop by our booth or schedule a meeting to see what we've been working on.

Security News
OWASP’s 2025 Top 10 introduces Software Supply Chain Failures as a new category, reflecting rising concern over dependency and build system risks.

Research
/Security News
Socket researchers discovered nine malicious NuGet packages that use time-delayed payloads to crash applications and corrupt industrial control systems.