0
# Server-Side Rendering
1
2
Server-side rendering with React Helmet allows you to extract head data after rendering your React app to include in the final HTML document. This is essential for SEO, social media sharing, and prerendering scenarios.
3
4
## Capabilities
5
6
### Static Head Data Extraction
7
8
Extract head data after server-side rendering to include in HTML documents.
9
10
```javascript { .api }
11
/**
12
* Extract head data after server-side rendering
13
* Must be called on server after ReactDOMServer.renderToString() or renderToStaticMarkup()
14
* @returns HelmetData object containing all head elements and attributes
15
*/
16
static renderStatic(): HelmetData;
17
18
/**
19
* Legacy alias for renderStatic()
20
* @deprecated Use renderStatic() instead
21
* @returns HelmetData object containing all head elements and attributes
22
*/
23
static rewind(): HelmetData;
24
25
interface HelmetData {
26
/** Document title element */
27
title: HelmetElement;
28
/** Base element */
29
base: HelmetElement;
30
/** Meta elements */
31
meta: HelmetElement;
32
/** Link elements */
33
link: HelmetElement;
34
/** Script elements */
35
script: HelmetElement;
36
/** Style elements */
37
style: HelmetElement;
38
/** Noscript elements */
39
noscript: HelmetElement;
40
/** HTML element attributes */
41
htmlAttributes: HelmetElement;
42
/** Body element attributes */
43
bodyAttributes: HelmetElement;
44
}
45
46
interface HelmetElement {
47
/**
48
* Convert to React components for JSX rendering
49
* @returns Array of React elements
50
*/
51
toComponent(): React.ReactElement[];
52
53
/**
54
* Convert to HTML string for server-side rendering
55
* @returns HTML string representation
56
*/
57
toString(): string;
58
}
59
```
60
61
**Usage Example:**
62
63
```javascript
64
import React from "react";
65
import ReactDOMServer from "react-dom/server";
66
import { Helmet } from "react-helmet";
67
import App from "./App";
68
69
// Render your app
70
const appString = ReactDOMServer.renderToString(<App />);
71
72
// Extract head data
73
const helmet = Helmet.renderStatic();
74
75
// Generate complete HTML
76
const html = `
77
<!DOCTYPE html>
78
<html ${helmet.htmlAttributes.toString()}>
79
<head>
80
${helmet.title.toString()}
81
${helmet.meta.toString()}
82
${helmet.link.toString()}
83
${helmet.script.toString()}
84
${helmet.style.toString()}
85
</head>
86
<body ${helmet.bodyAttributes.toString()}>
87
<div id="root">${appString}</div>
88
${helmet.noscript.toString()}
89
</body>
90
</html>
91
`;
92
```
93
94
### JSX Server Rendering
95
96
When using JSX for server-side HTML generation, use the `toComponent()` method:
97
98
```javascript { .api }
99
import React from "react";
100
import ReactDOMServer from "react-dom/server";
101
import { Helmet } from "react-helmet";
102
103
function HTMLDocument() {
104
// App must be rendered first to populate Helmet state
105
const appString = ReactDOMServer.renderToString(<App />);
106
const helmet = Helmet.renderStatic();
107
108
const htmlAttrs = helmet.htmlAttributes.toComponent();
109
const bodyAttrs = helmet.bodyAttributes.toComponent();
110
111
return (
112
<html {...htmlAttrs}>
113
<head>
114
{helmet.title.toComponent()}
115
{helmet.meta.toComponent()}
116
{helmet.link.toComponent()}
117
{helmet.script.toComponent()}
118
{helmet.style.toComponent()}
119
</head>
120
<body {...bodyAttrs}>
121
<div id="root" dangerouslySetInnerHTML={{ __html: appString }} />
122
{helmet.noscript.toComponent()}
123
</body>
124
</html>
125
);
126
}
127
```
128
129
### Testing Utilities
130
131
Get current Helmet state for testing without affecting the instance stack.
132
133
```javascript { .api }
134
/**
135
* Testing utility to get current state without resetting the mounted instance stack
136
* @returns Current HelmetData state
137
* @note Only use for testing purposes
138
*/
139
static peek(): HelmetData;
140
```
141
142
**Usage in Tests:**
143
144
```javascript
145
import { Helmet } from "react-helmet";
146
import { render } from "@testing-library/react";
147
148
test("helmet sets correct title", () => {
149
render(
150
<Helmet>
151
<title>Test Title</title>
152
</Helmet>
153
);
154
155
const helmetData = Helmet.peek();
156
expect(helmetData.title.toString()).toContain("Test Title");
157
});
158
```
159
160
### Environment Control
161
162
Control DOM usage detection for server environments.
163
164
```javascript { .api }
165
/**
166
* Controls DOM usage detection
167
* Set to false in server environments where DOM is not available
168
* @param value - Boolean indicating if DOM can be used
169
*/
170
static set canUseDOM(value: boolean);
171
```
172
173
**Usage:**
174
175
```javascript
176
import { Helmet } from "react-helmet";
177
178
// In server environment
179
Helmet.canUseDOM = false;
180
181
// In browser environment (default)
182
Helmet.canUseDOM = true;
183
```
184
185
## Complete Server Example
186
187
Here's a complete Express.js server example:
188
189
```javascript
190
import express from "express";
191
import React from "react";
192
import ReactDOMServer from "react-dom/server";
193
import { Helmet } from "react-helmet";
194
import App from "./App";
195
196
const app = express();
197
198
// Configure Helmet for server environment
199
Helmet.canUseDOM = false;
200
201
app.get("*", (req, res) => {
202
// Render the app
203
const appString = ReactDOMServer.renderToString(
204
<App url={req.url} />
205
);
206
207
// Extract head data
208
const helmet = Helmet.renderStatic();
209
210
// Send complete HTML
211
res.send(`
212
<!DOCTYPE html>
213
<html ${helmet.htmlAttributes.toString()}>
214
<head>
215
<meta charset="utf-8">
216
<meta name="viewport" content="width=device-width, initial-scale=1">
217
${helmet.title.toString()}
218
${helmet.meta.toString()}
219
${helmet.link.toString()}
220
${helmet.script.toString()}
221
${helmet.style.toString()}
222
</head>
223
<body ${helmet.bodyAttributes.toString()}>
224
<div id="root">${appString}</div>
225
${helmet.noscript.toString()}
226
<script src="/client.js"></script>
227
</body>
228
</html>
229
`);
230
});
231
232
app.listen(3000);
233
```
234
235
## Important Notes
236
237
### Memory Management
238
239
**Critical**: Always call `renderStatic()` or `rewind()` on the server to prevent memory leaks. React Helmet tracks mounted instances, and failing to extract the data will cause memory accumulation.
240
241
```javascript
242
// ❌ Memory leak - renderStatic() never called
243
app.get("/", (req, res) => {
244
const html = ReactDOMServer.renderToString(<App />);
245
res.send(`<html><body>${html}</body></html>`);
246
});
247
248
// ✅ Correct - renderStatic() extracts and clears state
249
app.get("/", (req, res) => {
250
const html = ReactDOMServer.renderToString(<App />);
251
const helmet = Helmet.renderStatic();
252
res.send(`<html><body>${html}</body></html>`);
253
});
254
```
255
256
### Webpack Externals
257
258
When using prebuilt app compilations, ensure the same react-helmet instance is used:
259
260
```javascript
261
// webpack.config.js
262
module.exports = {
263
externals: ["react-helmet"],
264
// ... other config
265
};
266
```
267
268
### Encoding Control
269
270
Control HTML entity encoding for server-side rendering:
271
272
```javascript
273
<Helmet encodeSpecialCharacters={false}>
274
<title>Title with <special> characters</title>
275
</Helmet>
276
277
// With encodeSpecialCharacters={true} (default):
278
// <title>Title with <special> characters</title>
279
280
// With encodeSpecialCharacters={false}:
281
// <title>Title with <special> characters</title>
282
```