Exploring Undocumented getInitialProps Properties on Next.js
Tags: react, javascript, node, nextjs
Published: 2020-05-01 09:44:44

*An adventure log on discovering the secrets of the getInitialProps function and its mysterious object properties — updated March 2020*

---

Table of contents:

- [Something’s not right 🔥](#somethings-not-right)
- [Inspecting and dumping ✨](#inspecting-and-dumping)
- [Type? What type? 🐴](#type-what-type)
- [Getting to know more 🚀](#getting-to-know-more)

---

Sometime around 2018, I was working on a web app using Next.js on an older version. At the time, one of the features of [Next.js](https://github.com/zeit/next.js) is that it supports initial data population using the [`getInitialProps` static method](https://nextjs.org/docs/api-reference/data-fetching/getInitialProps), which means that you can populate the page component `props` before loading the page (e.g. fetching news feeds).

The latest docs for Next.js is available on their [official website](https://nextjs.org/docs/getting-started). At [version 9.1.7](https://github.com/zeit/next.js/tree/v9.1.7) and before, the docs was published on GitHub. Specifically at the ["Fetching data and component lifecycle"](https://github.com/zeit/next.js/tree/v9.1.7#fetching-data-and-component-lifecycle) section, it shows how to use `getInitialProps` and what parameters that can be destructured. A snippet from their readme:

> `getInitialProps` receives a context object with the following properties:
> `pathname` - path section of URL
> `query` - query string section of URL parsed as an object
> `asPath` - `String` of the actual path (including the query) shows in the browser
> `req` - HTTP request object (server only)
> `res` - HTTP response object (server only)
> `err` - Error object if any error is encountered during the rendering

Before updating this post, `getInitialProps` has one additional property which you can read on their readme at [version 8.0.0 and below](https://github.com/zeit/next.js/tree/v8.0.0#fetching-data-and-component-lifecycle):

> `jsonPageRes` - [Fetch Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) object (client only)

Pretty straightforward, right? Except for one minor problem.

## Something’s not right 🔥

On another part of the readme which explains on [how to use a custom `App` component on `_app.js`](https://github.com/zeit/next.js/tree/v9.0.0#custom-app), it also uses `getInitialProps` but with different destructured context parameters. Here's the code snippet from the readme:

{% gist https://gist.github.com/grikomsn/af416c4c0d9ba600a9e718835ddb9a8d %}

From the snippet above, it shows that `getInitialProps` doesn't use the documented object properties. And also it seems that I'm not the only one confused about this. Quoting from a [discussion on a Spectrum thread](https://spectrum.chat/?t=07e9ab0e-0fae-43a8-8bc0-350c79e921a3),

> What damn are and where are coming from the following properties of the context parameter?

So for many weeks, I searched the codebase, issues, and even Spectrum threads related to `getInitialProps`. And in this post I will try my best to explain the `getInitialProps` debacle.

## Inspecting and dumping ✨

In [another Spectrum thread that I created](https://spectrum.chat/?t=bd0da841-05f0-4b3b-8f1f-9e6b16b1952b), @revskill recommends using `util.inspect` to analyze objects. So I made a temporary page (`pages/temp.js`) and use this snippet below to dump the `getInitialProps` parameter using `util.inspect` (note that this is Next.js before version 9):

{% gist https://gist.github.com/grikomsn/ee51f283ce1d48fa53fe4a758ea3ba9e %}

Checking the console, it returns this:

{% gist https://gist.github.com/grikomsn/843df9bb369609f8452bbb10fe502898 %}

All properties shown are already documented on the readme, so where's `Component`, `router`, and `ctx`? Because the readme shows that those three properties are used on a custom App, so I made pages/_app.js and dump the parameter on getInitialProps like before (again, note that this is before version 9):

{% gist https://gist.github.com/grikomsn/3692c9955c053f5267c0a26fdc29f5a8 %}

Now the console returns two logs:

{% gist https://gist.github.com/grikomsn/dce5f1f7658f6d047552718ad4142e7b %}

As you can see on the snippet above, I destructured two properties: `Component` and `ctx`. So from my understanding is that the `Component` object is the page component that will be loaded (e.g. `pages/index.js`), and the `ctx` object is the `App` context (which explains why it has a `router` property). Note the `if (Component.getInitialProps)`, it's quite obvious that what it does is checks whether the page component has a getInitialProps function to run.

So what that means is the `getInitialProps` parameter (or context) differs from a page component. But this doesn't explain another thing.

## Type? What type? 🐴

I’m a sucker for object types, so it really bothers me when statically adding `getInitialProps` to an `App` or page component obviously doesn't give any hints on my editor. And after inspecting a lot above, at some point I asked myself, "does `next` has a `@types` package?" [And they have!](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/5b30992fd59e4a145b7589f2b333673f231fd36f/types/next/index.d.ts) Why did I bother inspecting ony by one?

March 2020 update note: [DefinitelyTyped](https://github.com/DefinitelyTyped) has deprecated the Next.js typings since version 9 already includes its own TypeScript declaration file. You can [view the deprecation pull request on GitHub](https://github.com/DefinitelyTyped/DefinitelyTyped/pull/40235), courtesy of [Resi Respati](https://resir014.xyz/).

After that sudden realization, I added the type package and checked whether it has an object or interface with the name ‘context’ using the IntelliSense extensions on Visual Studio Code. Lo and behold, I found three interfaces ‘context’ related (remember that this is before version 9):

{% gist https://gist.github.com/grikomsn/5d950c5883f65590043c4bfe3aac13a7 %}

After finding those three, I tried type hinting the `getInitialProps` function on both `_app.js` and a page component, and the results was fantastic:

![App context object properties](https://miro.medium.com/max/875/0*-cLBxljNj-47AcFF.png)

<center>
  <small>👆🏻 App context object properties</small>
</center>

![Page context object properties](https://miro.medium.com/max/875/0*ya_uM_Fm8FQDQrcw.png)

<center>
  <small>👆🏻 Page context object properties</small>
</center>

Much better! Now I have found out that it has a `@types` package, getting to know more about its type and contents is much easier.

## Getting to know more 🚀

In Visual Studio Code, you can jump to the definition of the type by command or control clicking the variable like below:

![Preview on control or command clicking the object type](https://miro.medium.com/max/658/0*gq2q3Rku-imCRAJV.gif)

<center>
  <small>👆🏻 Preview on control or command clicking the object type</small>
</center>

From the GIF above, it opens the declaration files in the `node_modules` directory in `node_modules/@types/next`. Or you can view the file on the [`@types/next` repository on GitHub](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/5b30992fd59e4a145b7589f2b333673f231fd36f/types/next/index.d.ts). Here's a snippet from the declaration files for the context object on the `App` component (`NextAppContext`):

{% gist https://gist.github.com/grikomsn/e8ca577243a3f6ddfdc3f18202daf437 %}

And here’s the context declaration for page components (`NextContext`):

{% gist https://gist.github.com/grikomsn/b066b8967584641f3d7fe8b41e34acb3 %}

That’s much better than inspecting objects one by one. 😅

---

Hopefully this adventure log isn’t that confusing, since `getInitialProps` is already confusing at the start. Thanks for reading, and happy coding! 👋🏻

[*This was originally posted at Medium on November 26th, 2018 with the same title and contents.*](https://medium.com/@griko/exploring-undocumented-getinitialprops-properties-on-next-js-1265a6abc652)