This week I was trying to access the ctx.req
property on a _document
, but the value kept showing up as undefined
. I tried the most basic example that they showed in their docs:
class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx);
// Expecting headers, cookies, etc, but it's undefined.
console.log(ctx.req);
return initialProps;
}
render() {
return (
<Html>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
export default MyDocument;
Why is ctx.req
undefined on a server-side only process? The Next.js docs say about the custom _document
:
This file is only rendered on the server
💡 Well, it turns out that another page rendered lower in the tree by <Main />
must invoke getServerSideProps
first. For example, adding this to pages/index.tsx
:
export const getServerSideProps = async (_ctx: GetServerSidePropsContext) => {
/**
* Yep, it's empty, but needed to force reading cookies and request
* headers on server-side so _document can read it
*/
return { props: {} };
};
Yep, and now all of a sudden, the full request object is available on ctx.req
inside the custom _document
!
It matters which route/page you’re accessing. So, adding getServerSideProps
to pages/index.tsx
won’t mean that _document
will behave the same on pages/login.tsx
. You’d need to add getServerSideProps
on that page as well.