Custom Document

A custom Document is commonly used to augment your application's <html> and <body> tags. This is necessary because Next.js pages skip the definition of the surrounding document's markup.

A custom Document can also include getInitialProps for expressing asynchronous server-rendering data requirements.

To override the default Document, create the file ./pages/_document.js and extend the Document class as shown below:

import Document, { Html, Head, Main, NextScript } from 'next/document'

class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const initialProps = await Document.getInitialProps(ctx)
    return { ...initialProps }
  }

  render() {
    return (
      <Html>
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    )
  }
}

export default MyDocument

<Html>, <Head />, <Main /> and <NextScript /> are required for the page to be properly rendered.

Custom attributes are allowed as props, like lang:

<Html lang="en">

The ctx object is equivalent to the one received in getInitialProps, with one addition:

  • renderPage: Function - a callback that runs the actual React rendering logic (synchronously). It's useful to decorate this function in order to support server-rendering wrappers like Aphrodite's renderStatic

Caveats

  • Document is only rendered in the server, event handlers like onClick won't work
  • React components outside of <Main /> will not be initialized by the browser. Do not add application logic here. If you need shared components in all your pages (like a menu or a toolbar), take a look at the App component instead
  • Document's getInitialProps function is not called during client-side transitions, nor when a page is statically optimized
  • Make sure to check if ctx.req / ctx.res are defined in getInitialProps. Those variables will be undefined when a page is being statically exported by Automatic Static Optimization or by next export
  • Common errors include adding a <title> in the <Head /> tag or using styled-jsx. These should be avoided in pages/_document.js as they lead to unexpected behavior

Customizing renderPage

It should be noted that the only reason you should be customizing renderPage is for usage with css-in-js libraries that need to wrap the application to properly work with server-side rendering.

It takes as argument an options object for further customization:

import Document from 'next/document'

class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const originalRenderPage = ctx.renderPage

    ctx.renderPage = () =>
      originalRenderPage({
        // useful for wrapping the whole react tree
        enhanceApp: (App) => App,
        // useful for wrapping in a per-page basis
        enhanceComponent: (Component) => Component,
      })

    // Run the parent `getInitialProps`, it now includes the custom `renderPage`
    const initialProps = await Document.getInitialProps(ctx)

    return initialProps
  }
}

export default MyDocument