An adventure log on discovering the secrets of the getInitialProps function and its mysterious object properties — updated March 2020
Table of contents:
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 is that it supports initial data population using the
getInitialProps static method, 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. At version 9.1.7 and before, the docs was published on GitHub. Specifically at the "Fetching data and component lifecycle" section, it shows how to use
getInitialProps and what parameters that can be destructured. A snippet from their readme:
getInitialPropsreceives a context object with the following properties:
pathname- path section of URL
query- query string section of URL parsed as an object
Stringof 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:
jsonPageRes- Fetch Response object (client only)
Pretty straightforward, right? Except for one minor problem.
On another part of the readme which explains on how to use a custom
App component on
_app.js, it also uses
getInitialProps but with different destructured context parameters. Here's the code snippet from the readme:
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,
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
In another Spectrum thread that I created, @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):
Checking the console, it returns this:
All properties shown are already documented on the readme, so where's
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):
Now the console returns two logs:
As you can see on the snippet above, I destructured two properties:
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.
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! Why did I bother inspecting ony by one?
March 2020 update note: 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, courtesy of Resi Respati.
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):
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
👆🏻 Page context object properties
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.
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
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. Here's a snippet from the declaration files for the context object on the
App component (
And here’s the context declaration for page components (
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! 👋🏻