--- title: 'Server Side Rendering' --- Server side rendering in Emotion 10 has two approaches, each with their own trade-offs. The default approach works with streaming and requires no additional configuration, but does not work with nth child or similar selectors. It's strongly recommended that you use the default approach unless you need nth child or similar selectors. ## Default Approach Server side rendering works out of the box in Emotion 10 and above if you're only using `@emotion/react` and `@emotion/styled`. This means you can call React's [`renderToString`](https://reactjs.org/docs/react-dom-server.html#rendertostring) or [`renderToNodeStream`](https://reactjs.org/docs/react-dom-server.html#rendertonodestream) methods directly without any extra configuration. ```jsx import { renderToString } from 'react-dom/server' import App from './App' let html = renderToString() ``` The rendered output will insert a `
Text
``` > Warning: This approach can interfere with nth child and similar selectors as it inserts style tags directly into your markup. You will get a warning if you use such selectors when using this approach. ## Advanced Approach > Note: If you're not using nth child or similar selectors, you don't need to do this. Use the default approach. You can also use the advanced integration, it requires more work but does not have limitations on nth child and similar selectors. This approach does not work with the streaming APIs. ### On server #### When using `@emotion/react` ```jsx import { CacheProvider } from '@emotion/react' import { renderToString } from 'react-dom/server' import createEmotionServer from '@emotion/server/create-instance' import createCache from '@emotion/cache' const key = 'custom' const cache = createCache({ key }) const { extractCriticalToChunks, constructStyleTagsFromChunks } = createEmotionServer(cache) const html = renderToString( ) const chunks = extractCriticalToChunks(html) const styles = constructStyleTagsFromChunks(chunks) res .status(200) .header('Content-Type', 'text/html') .send(` My site ${styles}
${html}
`); ``` #### When using `@emotion/css` ```jsx import { CacheProvider } from '@emotion/react' import { renderToString } from 'react-dom/server' import createEmotionServer from '@emotion/server/create-instance' import createCache from '@emotion/cache' const key = 'custom' const cache = createCache({ key }) const { extractCritical } = createEmotionServer(cache) let element = ( ) let { html, css, ids } = extractCritical(renderToString(element)) res .status(200) .header('Content-Type', 'text/html') .send(` My site
${html}
`); ``` ### On client ```jsx // Hydration of the ids in `data-emotion-css` will automatically occur when the cache is created const cache = createCache() ReactDOM.hydrate( , document.getElementById('root') ) ``` In this approach you have to create your own cache and emotion server then use extractCritical ## API Reference ### renderStylesToString This returns a string of html that inlines the critical css required right before it's used. ```jsx import { renderToString } from 'react-dom/server' import { renderStylesToString } from '@emotion/server' import App from './App' const html = renderStylesToString(renderToString()) ``` ### renderStylesToNodeStream This returns a [Node Stream Writable](https://nodejs.org/api/stream.html#stream_class_stream_writable) that can be used to insert critical css right before it's required. This can be used with [React's streaming API](https://reactjs.org/docs/react-dom-server.html#rendertonodestream). ```jsx import { renderToNodeStream } from 'react-dom/server' import { renderStylesToNodeStream } from '@emotion/server' import App from './App' const stream = renderToNodeStream().pipe(renderStylesToNodeStream()) ``` ### extractCritical This returns an object with the properties `html`, `ids` and `css`. It pulls out Emotion rules that are actually used in the rendered HTML, but it still includes all global rules because they don't appear in the rendered HTML as they might affect any elements on the page. > Note: > > If you have dynamic global styles it's advised to create cache **per** single render to avoid global styles from different renders leaking into the extracted `css`. ```jsx import { renderToString } from 'react-dom/server' import { extractCritical } from '@emotion/server' import App from './App' const { html, ids, css } = extractCritical(renderToString()) ``` #### hydrate `hydrate` should be called on the client with the `ids` that `extractCritical` returns. If you don't call it then Emotion will reinsert all the rules. `hydrate` is **only** required for `extractCritical`, **not** for `renderStylesToString` or `renderStylesToNodeStream`, hydration occurs automatically with `renderStylesToString` and `renderStylesToNodeStream`. ```jsx import { hydrate } from '@emotion/css' hydrate(ids) ``` ## Next.js To use emotion's SSR with Next.js you need a custom `Document` component in `pages/_document.js` that renders the styles and inserts them into the ``. [An example of Next.js with emotion can be found in the Next.js repo](https://github.com/vercel/next.js/tree/master/examples/with-emotion-vanilla). > Note: > > This only applies if you're using vanilla Emotion or a version of Emotion prior to v10. For v10 and above, SSR just works in Next.js. ## Gatsby To use emotion's SSR with Gatsby, you can use `gatsby-plugin-emotion` or you can do it yourself with emotion and Gatsby's various APIs but it's generally recommended to use `gatsby-plugin-emotion`. [There's an example available in the Gatsby repo](https://github.com/gatsbyjs/gatsby/tree/master/examples/using-emotion) or [you can look at this site which is built with Gatsby!](https://github.com/emotion-js/emotion/tree/main/site) ```bash yarn add gatsby-plugin-emotion ``` gatsby-config.js ```jsx module.exports = { plugins: [...otherGatsbyPlugins, 'gatsby-plugin-emotion'] } ``` If using a [custom cache](./cache-provider), ensure you are creating a new cache per server render within `gatsby-ssr.js`. This will differ from the implementation within `gatsby-browser.js`. create-emotion-cache.js ```jsx import createCache from '@emotion/cache' export const createMyCache = () => createCache({ key: 'my-prefix-key', stylisPlugins: [ /* your plugins here */ ], }) export const myCache = createMyCache() ``` gatsby-ssr.js ```jsx import { CacheProvider } from '@emotion/react' import { createMyCache } from './create-emotion-cache' export const wrapRootElement = ({ element }) => ( {element} ) ``` gatsby-browser.js ```jsx import { CacheProvider } from '@emotion/react' import { myCache } from './create-emotion-cache' export const wrapRootElement = ({ element }) => ( {element} ) ``` > Note: > > While Emotion 10 and above supports SSR out of the box, it's still recommended to use gatsby-plugin-emotion as gatsby-plugin-emotion will enable @emotion/babel-plugin and other potential future optimisations. ## Puppeteer If you are using Puppeteer to prerender your application, emotion's `speedy` option has to be disabled so that the CSS is rendered into the DOM. index.js ```jsx // This has to be run before emotion inserts any styles so it's imported before the App component import './disable-speedy' import ReactDOM from 'react-dom' import App from './App' const root = document.getElementById('root') // Check if the root node has any children to detect if the app has been prerendered if (root.hasChildNodes()) { ReactDOM.hydrate(, root) } else { ReactDOM.render(, root) } ``` disable-speedy.js ```js import { sheet } from '@emotion/css' // Check if the root node has any children to detect if the app has been preprendered // speedy is disabled when the app is being prerendered so that styles render into the DOM // speedy is significantly faster though so it should only be disabled during prerendering if (!document.getElementById('root').hasChildNodes()) { sheet.speedy(false) } ``` > Note: > > The `sheet.speedy` call has to be run before anything that inserts styles so it has to be put into it's own file that's imported before anything else.