# React SSR

React Server SideRendering (SSR).

Published: 2026-05-14
Tags: ssr, vyriy, react
Source: https://vyriy.dev/examples/react-ssr/

---

# React Server Side Rendering (SSR)

## Typescript

In our time it's easy to make react SSR using only Typescript.

Create directory

```bash
mkdir react-ssr-ts
cd react-ssr-ts
```

Init project

```bash
yarn init -y
echo "nodeLinker: node-modules" > .yarnrc.yml
touch yarn.lock
```

Dependencies

```bash
yarn add react react-dom typescript @types/react @types/react-dom
```

tsconfig.json

```json
{
  "compilerOptions": {
    "target": "es2020",
    "module": "commonjs",
    "jsx": "react-jsx",
    "strict": true,
    "skipLibCheck": true
  },
  "include": ["index.tsx"]
}
```

index.tsx

```tsx
import * as React from 'react';
import { renderToString } from 'react-dom/server';

const App = () => <div>App</div>;

console.log(renderToString(<App />));
```

Run

```bash
tsc && node index
```

Result

```html
<div>App</div>
```

## Vyriy

Pure TypeScript is enough for a small SSR example, but for production SSR a bundler is usually safer.
The TypeScript compiler transpiles files, but it does not bundle or validate the full runtime dependency graph.
With a bundler you run the server from the same resolved module graph that was checked during build: ESM/CommonJS interop, JSX transform, package exports, aliases, side-effect imports and external dependencies are handled in one place.
It also gives you a predictable server artifact in `dist`, which is easier to test, deploy and compare in consumer tests.

The same we can make with Vyriy.

Create directory

```bash
mkdir react-ssr-vyriy
cd react-ssr-vyriy
```

Init project

```bash
yarn init -y
echo "nodeLinker: node-modules" > .yarnrc.yml
touch yarn.lock
```

Dependencies

```bash
yarn add react react-dom typescript @types/react @types/react-dom
yarn add @vyriy/webpack-config @vyriy/typescript-config webpack
```

tsconfig.json

```json
{
  "extends": "@vyriy/typescript-config/index.json",
  "include": ["index.tsx"]
}
```

index.tsx

```tsx
import { renderToString } from 'react-dom/server';

const App = () => <div>App</div>;

console.log(renderToString(<App />));
```

webpack.config.mjs

```mjs
import 'webpack';

import { ssr } from '@vyriy/webpack-config';

export default ssr('./index.tsx', {
  filename: 'index.js',
  library: { type: 'commonjs2' },
  clean: true,
});
```

Run

```bash
webpack && node dist
```

Result

```html
<div>App</div>
```

So yes, the bundler version has more code and one more config file.
But this extra code is not accidental ceremony: it moves important runtime decisions into the build step.
For SSR this is worth it because server rendering fails late and often in places that TypeScript alone does not model: package resolution, module format interop, side effects, missing files and dependencies that behave differently after publish.

The result is a stronger contract.
If webpack builds the SSR entry, you know the server artifact can be executed from `dist` with the same dependency graph that your consumer or deployment will use.
That makes the example a little longer, but the production story simpler: build once, test the built file, deploy the built file.

This is where Vyriy helps: the library takes the complicated webpack and TypeScript choices into shared configuration.
The application keeps a small `webpack.config.mjs`, a normal TypeScript entry file and a plain `webpack && node dist` command.
So the coding and build process stays simple, calm and reliable, while the hard parts are still handled deliberately.
