Next JS Server Side Rendering (SSR)

Next.js is a great framework that offers many features for enhancing NextJS SEO optimization and user-experience. One staple feature is server side rendering (SSR), which is essentially what the name implies. Much of the work needed to render your web page into HTML is handled on the server rather than the client.           

Why is this significant? Well, NextJs is built on top of the React framework, and the React framework is typically used to build single page applications (SPAs). The default configuration for React SPAs is to only serve a barebones HTML shell to the client at first render, and subsequently send a bunch of Javascript files that finishes populating the HTML page with the actual content.

SEO Consultant

Free Weekly SEO Newsletter

Hey! I’m Scott, I’ve been an SEO consultant for nearly 10 years. Get on my weekly newsletter to get..

  • Weekly SEO updates, keep up with the latest and greatest.
  • How we grow websites from zero to millions of visitors
  • A bunch of SEO tips and Tricks you won’t find anywhere else test

TL;DR: Next JS SSR & Quick Links

React SPA | Good for UX — Bad for SEO

This design pattern is great for developers, and is pretty good for user-experience in most cases as well (unless you have a terribly slow internet connection). However, GoogleBot isn’t too crazy about it, because Google’s crawlers want content fast, and waiting on all that Javascript to load isn’t conducive to serving up content quickly.

What is SSR | A More In-Depth Discussion

SSR can differ greatly depending on the framework in question. In general, SSR is simply the rendering of HTML pages on the server. Using NextJs, that’s only part of the story.

How NextJs Handles SSR

NextJs has its own flavor of SSR that meshes well with the underlying React framework. First of all, when a page request is made to a NextJs app, one of two life cycle methods gets called. The method that tells Next to render the page on the server is called getServerSideProps.

This method allows the developer to do all kinds of cool stuff other than just telling Next to render on the server, such as injecting page related data on a per-request basis from an external API into the component props.

However, the key feature that really sets NextJs apart from other non-React SSR technologies is its ability to ship code bundles with the generated HTML in a very efficient manner using next/dynamic imports with Suspense for lazy loading.

Lazy Loading vs Eager Loading

When making explicit imports into your components, they are eager loaded. This means all resources are loaded as soon as the code is executed. This isn’t ideal for optimizing page load speed, because certain resource intensive components can often be loaded later on.

Here’s a truncated example of explicit importing that results in eager loading:

import OneComponent from './OneComponent';
import TwoComponent from './TwoComponent';
 
export default function Home() {
  return (
    <>
        <OneComponent />
        <TwoComponent />
    </>
)}

In contrast, lazy loading is a design pattern that allows certain pieces of code, React components in our case, to be prioritized and loaded only once other parts of the page have completed loading. NextJs offers the next/dynamic library and Suspense component to achieve lazy loading.

Here’s a truncated example of lazy loading with next/dynamic and Suspense:

import dynamic from 'next/dynamic';
import { Suspense } from 'react';
import OneComponent from './OneComponent';
 
const TwoComponent = dynamic(() => import('./TwoComponent'), {
  suspense: true,
});
 
export default function Home() {
  return (
    <>
      <OneComponent />
      <Suspense fallback={`Loading...`}>
         <TwoComponent />
    </Suspense>
    </>
  )

In this example, TwoComponent is loaded only after OneComponent has finished loading. I.e It is loaded lazily.

Why is Code Bundling and Dynamic Imports so Important for SSR and SEO?

Imagine you’ve built a really cool super interactive app using NextJs, and your first client page request just came in. NextJs can then render the HTML, and include a few script tags pointing to all your fancy JavaScript that makes the page so interactive. Great! Well, not really. Your JavaScript files are probably going to be pretty bloated, and all that extra time waiting for the scripts to arrive is no good for SEO metrics.

In comes dynamic imports and lazy loading. NextJs allows the developer to specify which script imports can wait, and which cannot, using the next/dynamic library.

next/dynamic is an extension of React.lazy, and is therefore used with Suspense to achieve delayed hydration within your components.

Real-World Example of Dynamic Imports Impacting SEO

Let’s say you have a complex modal box component with a 3d model inside that’s wired up to a button click at the bottom of a page. Logically, there’s no need to waste bandwidth packaging up this component and shipping it with your initial render. It will never be needed until well after your browser loads the initial content, and the user decides to scroll down and check stuff out.

Using the next/dynamic library, we can tell NextJs to split the component code into a separate chunk, and lazy load it only after the important content has already finished loading. In other words, we can prioritize which scripts get loaded immediately, and which do not, in order to maximize page speed.

This functionality has a tremendous impact in terms of SEO performance and scalability. It’s features such as this that make NextJs a solid frontrunner in the race of React based frameworks.

Optimizing Images on the Fly With SSR and NextJs Image

The formula here is simple: Larger image files equals slower page speed and less SEO performance.

Another great feature of SSR is the ability to do Next Js image optimization on the fly. Not all frameworks include built-in functionality for handling this, whereas NextJs comes locked and loaded with the Image component.

As a developer, it can be tedious receiving non-optimized images from a client to be placed on their site. The image must be processed through an image optimization engine such as squoosh, contributing to a less efficient development workflow.

The NextJs Image component automates the process, taking your image during the SSR process and optimizing it prior to sending it to the client. It even streamlines the process of caching on content delivery networks, adding an extra SEO bonus.

Troubleshooting Slow NextJs Pages That Use SSR

It’s not uncommon for developers new to NextJs to experience slower page speed than what they’ve come to expect in a React app. This isn’t because NextJs is inherently flawed, but rather because optimization techniques have probably been neglected.

This isn’t just annoying for the end-user, it also sucks for SEO and is a problem that must be considered priority.

Here’s some things to look for in your NextJs app if it just seems like things aren’t moving quick enough:

  1. Ensure any external API calls are handled in the most efficient manner possible. This lag is more noticeable on SSR apps in particular, because the API call must finish before the response is sent to the client. Of course, there’s ways to mitigate this lag if the API call cannot be optimized (Lazy/Suspense), but always look to optimize any external calls and return only the necessary data.
  2. Starting with React 18 and onward, we can now utilize Lazy/Suspense on the server. This is a great feature that allows developers to specify components that should only load after all other non specified components are finished loading. This concept is similar to the dynamic imports we discussed earlier, but is actually more intuitive and easier to use.
  3. Lack of image optimization is a common culprit when experiencing slow page speed. This is one of the easiest and most effective optimizations using NextJs. Check for any images over 100kb in size; chances are you can cut this in half (or more) using the NextJs Image component.
  4. Cache frequently used content. This probably isn’t a cause of slow page speed with SSR, but using CDNs or preloaders can garner significant performance increases. After other internal optimizations, it’s a good idea to look into this feature to further increase the SEO and UX performance of your site.

NextJs App Won’t Server Side Render

If you’re trying to achieve SSR with Next unsuccessfully, you’ve probably run into one of the following problems:

  1. Your app is being rendered as a client side SPA:
    In this case, first ensure you’ve added the getServerSideProps lifecycle method to the page component in question. If that didn’t solve your problem, start by getting rid of each higher order component (HOC) one at a time, while checking if SSR kicks in after each removal. When it does, you’ve probably found an issue with a third party library, such as a redux provider, that’s causing a compatibility issue with NextJs SSR functionality. Check into the documentation, github issues, and check the versions. Usually such issues can be resolved with a little digging.
  2. Your app is being statically generated:
    Usually, this is simply a matter of ensuring you’re using getServerSideProps instead of getStaticProps within the page component in question.

What is Static Site Generation?

The fastest way for a server to serve a web page is if the page requested exists on the server as a static HTML file. No rendering or runtime magic; the HTML file is already there awaiting a request.

That’s what static site generation (SSG) accomplishes. At build time, each page component is rendered into HTML, then an actual HTML file is ‘generated’ and served from your hosting provider.

SSG can outperform SSR in terms of overall SEO performance. However, SSG lacks flexible scalability because when changes are made, each HTML page must be regenerated and served out. This isn’t feasible for a highly dynamic site such as an action site or social media platform.

NextJs SSR | Overview and Concluding Thoughts

As we’ve demonstrated, SSR is simply a design pattern that delegates much of the work to the server when building dynamic web apps. It’s a strong design pattern because, when done properly, you can achieve fast page speed and great UX without compromising important SEO metrics.

NextJs accomplishes performant SSR by coming equipped with powerful optimization tools such as next/dynamic and the Next Image component. Many complex tasks such as code splitting and lazy loading are streamlined by Next, making it a great choice for teams looking to minimize overhead while not losing a ton of flexibility.

Overall, NextJs and their unique flavor of SSR comes highly recommended. Give it a try using the concepts within this article; you won’t be disappointed.

Leave a Comment

oh my crawl logo
Digital Architecture
For Search Engines
Contact
Brooklyn, NY 11219

Blog