Image by adrienolichon on Unsplash

Data Fetching with Next JS-Demystified

Ellon
Towards Dev
Published in
7 min readJan 21, 2022

--

Current generation JavaScript applications have drastically improved user experience — delivering fast content delivery with imperceptible load times. Recently, more and more pages are being dynamically re-written; taking advantage of the Single Page Architecture, rather than using the standard ‘request-response’ model which involved server-side languages (Python, PHP..) processing responses to HTTP calls from browsers. Client-only rendering has enabled this, through frameworks such as React, Vue, Ember.js, etc. These technologies allow everything to be rendered from the client-side, and most of the time, this approach works well and is pretty fast. However, more modern solutions guarantee better, faster and more scalable applications.

The new viewpoint of the term Server Side Rendering is described by a technique that imposes the rendering of client-side SPA’s (Single Page Applications) on the server — and then the sending of fully rendered pages to the client. This enables dynamic, heavy, front-end components to be served as HTML markup. This is not only a performance boost, but also enables the creation of applications that can be crawled for their content by web crawlers — even those that don’t execute JavaScript code. This boosts the SEO (Search Engine Optimization) of the application and aids the provision of metadata to social media channels.

Next.js is the more popular solution for achieving this greater dynamism through Server Side Rendering. Operating only on React Applications, and making use of the isomorphic web application architecture to blend server-rendered web applications with SPA’s, it has become the predominant herald of fast perceived performance, seamless UX and SEO-friendly rendering.

Aside from Server Side Rendering, Next.js additionally achieves application dynamism through Static Site Generation (SSG). Static websites were prevalent majorly in the first generation of the world wide web — where information was only displayed in basic HTML pages for read-only purposes. Static sites are as old as the web itself. They lacked any dynamic representation, until recently, after technologies and tools have drastically improved over the years. They have regained their popularity, with generators such as Next.js, Gatsby, Hugo, Nuxt.js and Jekyll gaining traction. As websites grew over the years, delivering more content and achieving better user interaction and dynamism, the process of web application development became more and more efficient. Web servers could store enormous amounts of files that could be fetched on demand by users. The servers would faithfully combine templates and content, apply loops and logic, integrate and operate seamlessly with databases to return page views when they were requested.

What Static Side Generators do is exactly what traditional web applications did, and still do. JavaScript based web apps work by running libraries/scripts linked at the HTML file(s) at runtime in the browser. Normally when the browser receives a page, its just simple HTML. Only after the browser receives the page, does it generate a view by applying data and content into the page from the scripts. In contrast to this, what Static Site Generators such as Next.js do is that they try to render the page — just as it would normally on the browser, but at compile time. They generate the page ahead of time, and do so for every single possible view at build time so that they are ready to serve ahead of time. The beauty in this is that it shifts the focus from ‘request time’ to ‘build time’. Knowing this, the difference between Server Side Rendering and Static Site Generation is distinct. Both these SSR and SSG approaches involve rendering and generating HTML. They both aim at improving performance as well as SEO, but the clear difference is that Static Rendering happens once, at build time, for each page, ahead of time — while Server Rendering happens on demand, after a request.

Static Site Rendering Flow

Let’s take a deeper look at how Next.js utilizes the above discussed approaches to fetch data and render content on the browser.

1. Server Side Rendering

To fetch data at request time, Next offers a function known as getServerSideProps

export async function getServerSideProps() {
const res = await fetch(`https://.../data`)
const data = await res.json()

if (!data) {
return {
notFound: true,
}
}

return {
props: { data },
}
}

Any fetch data is returned as the component’s props. Here, the notFound option returns a 404 error page if no data is found after the call to the server.

In use, this function pre-renders a page on every request, unless the result is cached by a CDN. Server Side Rendering caching improves the response times and reduces the number of requests made to external services. Next.js offers a way to specify caching rules for pages and static assets such as images, through cache-control headers, set in the next.config.js file (a configuration settings module used by the Next.js server and build phase).

Keep in mind that by using getServerSideProps to fetch our data, the server must compute results on every request, and so this approach is considerably slower than Static Generation. The importance of caching results plays a big part when using getServerSideProps to improve response times; however, if in any way your data can be fetched on the client side and you do not necessarily need to pre-render it, avoid using getServerSideProps.

2. Static Site Generation

Next.js offers another function known as getStaticProps for Static Site Rendering. It uses the props returned by whatever content is provided in this function to pre-render a page at build time ahead of a user’s request. This is most commonly used when needing to fetch data from a CMS.

export async function getStaticProps() {
const res = await fetch(`https://.../data`)
const data = await res.json()

if (!data) {
return {
notFound: true,
}
}

return {
props: { data },
}
}

Its also good to note that if you use getStaticProps and in any way your application has logic that is shared between pages, for example JWT Authentication — in addition to getStaticProps, a middleware function is needed. This is because getStaticProps runs at build time. It generates static HTML and so it cannot access incoming user requests. A middleware file can be created (to store the middleware function) inside the /pages directory, where all your applications pages are stored, and it will run on all routes within.

In addition to the HTML page file, pre-rendering a page with getStaticProps generates a JSON file which holds the result of running getStaticProps. This JSON file is used in client side routing. When navigating to pre-rendered pages using getStaticProps, this JSON file is fetched and used as props for the page component — meaning that during page transitions, only this JSON is used, and getStaticProps does not get called.

Other things to keep in mind..

  • One, this function is majorly a production function. When running next dev on the console during development, getStaticProps will be called on every request.
  • Moreover, getStaticProps can only be exported as a standalone function. If you wrap it in another function and export that outer function, it will not work as you intend it to.
  • And finally, for apparent reasons, this function can only be exported from a page. If you define it from outside the /pages directory, no good comes of it. In actuality, react might just throw an error when it happens.

3. Dynamic Routing and static paths

getStaticPaths is also another function Next.js provides for Static Site Generation. When pages have dynamic routing, a lot of paths have to be defined if these pages use getStaticProps. By exporting a function known as getStaticPaths from a page that uses dynamic routes, Next.js will statically pre-render all the paths specified inside of it.

export async function getStaticPaths() {
return {
paths: [
{ params: { ... } }
],
fallback: false
};
}

The paths key determined with pathswill be pre-rendered during next build

return {
paths: [
{ params: { id: '1' } },
{ params: { id: '2' } }
],
fallback: ...
}

There’s also a fallback option as seen above, which if set to false, any path not returned by getStaticPaths will result in a 404 error page. If it’s set to true, then the paths not returned by this function will not result in a 404 error page. Instead, Next.js will serve a fallback version of the page on the first request of the path — then in the background, it will statically generate the path’s HTML and JSON which will be received by the browser. The received JSON is used automatically to render the page with the required props. From the perspective of the user, the fallback page will be swapped to the full generated page. After this, subsequent requests to this similar path will serve the full generated page, like the other pages pre-rendered at build time. Setting fallback to true is useful if an application is large and contains many dynamic routes, such as an ecommerce site. It would be desirable, in such cases to statically generate just a small subset of pages, then use fallback: true for the rest.

Through the above three functions, it is clear how Next.js leverages its different API’s to achieve both static and dynamic user experiences. Then again, there are many different tools that offer SSG and SSR besides Next.js. Depending on the project at hand, the languages an individual or a team specialize in, the complexity of the code written or be it just personal preference, the end goal is not just creating a snappy site with crazy fast response times. What’s most important is generating a site that’s synchronous with your productivity workflow and best fits the user’s needs.

Learn More:

Read Next.js docs here

Read more about the Next Middleware here

--

--