Sitecore Next.js App Router: Part 3, Performance

Anton Tishchenko
Anton Tishchenko
Cover Image for Sitecore Next.js App Router: Part 3, Performance

Thanks to Sitecore PoC, we were able to run the Next.js App Router. The website was based on client components. All crucial parts were marked with use client directives.

We made it run on server components to get the benefits of the App Router that we wanted.

Now, it is time to measure performance. Is the App Router faster? It should be faster: code is executed only on the server, there is less client code, and requests should be cached. Rights? Let’s check it!

Testing Methodology

I have a Sitecore instance, running locally that will be the source of data for our websites.

The first website will be Sitecore Next.js App Router when many components are marked with use client. The second website will be Sitecore Next.js App Router based on server components. The third website will be Sitecore Next.js Pages Router based on the official release of Sitecore JSS.

All websites are deployed to Vercel. They will be built using Static Site Generation (SSG). It will allow us to avoid any influence of local machine speed on the test results. HTML will be generated during the build time.

I will use Lighthouse CLI to run tests. I will run a test on each website 5 times, to avoid mistakes in the results. Actually, tests of websites that are deployed to Vercel show constant and reproducible results. But, just in case, we will run each test 5 times and get the average value.

Testing script, in case you would like to check it by yourself:

const spawnSync = require("child_process").spawnSync;
const lighthouseCli = require.resolve("lighthouse/cli");

const websites = {};
websites["Pages Router"] =
  "http://sitecore-nextjs-pages-router.vercel.app/styleguide";
websites["App Router Client"] =
  "https://sitecore-nextjs-app-router-client.vercel.app/en/styleguide";
websites["App Router Server"] =
  "https://sitecore-nextjs-app-router-server.vercel.app/en/styleguide";

for (const [key, value] of Object.entries(websites)) {
  const results = [];
  for (let i = 0; i < 5; i++) {
    console.log(`Running Lighthouse attempt #${i + 1}...`);
    const { status = -1, stdout } = spawnSync("node", [
      lighthouseCli,
      value,
      "--output=json",
      "--chrome-flags=\"--headless\"",
    ]);
    if (status !== 0) {
      console.log("Lighthouse failed, skipping run...");
      continue;
    }
    results.push(JSON.parse(stdout));
  }
  const average = results.reduce((acc, result) => {
    return {
      categories: {
        performance: {
          score: acc.categories.performance.score + result.categories.performance.score,
        },
      },
    };
  });
  console.log(`Average performance score for ${key} was`, average.categories.performance.score * 100 / results.length);
}

SSG Results

I ran the test multiple times. And I got unexpected results for me. Sitecore Next.js website based on the Pages Router is faster than Sitecore Next.js website based on the App Router.

I expected that the Next.js App Router website, where everything is marked as use client would be slower, and using server components would make it faster. But I didn’t expect that it would be still slower than Sitecore Next.js Pages Router.

SSG App Router, client components App Router, server components Pages Router
Performance Performance Performance Performance
SI (Speed Index) Speed Index Speed Index Speed Index
CLS (Cumulative Layout Shift) Cumulative Layout Shift Cumulative Layout Shift Cumulative Layout Shift
TBT (Total Blocking Time) Total Blocking Time Total Blocking Time Total Blocking Time
LCP (Largest Contentful Paint) Largest Contentful Paint Largest Contentful Paint Largest Contentful Paint
FCP (First Contentful Paint) First Contentful Paint First Contentful Paint First Contentful Paint

Maybe SSR?

I heard a few opinions that App Router is designed to work better with the Server-side Rendering (SSR) approach. I think that this belief is based on how many Vercel is talking about caching of data and requests. I decide to run the SSR test as well. It will not be isolated as it was with SSG. There will be an influence of local machines. But I will run it many times to make sure that results are reproducible.

SSR Results

I got unexpected results for the second time. Again Sitecore Next.js Pages Router was the fastest. I didn’t check, but I think, it is caused by Next.js not caching requests to the layout service, because of not using fetch for making requests to the Sitecore layout service. Sitecore Next.js App Router based on the server component was faster than Sitecore Next.js App Router. This part was expected. Server components are faster than client components.

SSR App Router, client components App Router, server components Pages Router
Performance Performance Performance Performance
SI (Speed Index) Speed Index Speed Index Speed Index
CLS (Cumulative Layout Shift) Cumulative Layout Shift Cumulative Layout Shift Cumulative Layout Shift
TBT (Total Blocking Time) Total Blocking Time Total Blocking Time Total Blocking Time
LCP (Largest Contentful Paint) Largest Contentful Paint Largest Contentful Paint Largest Contentful Paint
FCP (First Contentful Paint) First Contentful Paint First Contentful Paint First Contentful Paint

Conclusion

You should not expect that you will get any performance boost once Sitecore JSS Next.js switches to App Router. Indeed, probably, you will even get a performance decrease. And getting a performance boost will be in your hands. You will need to do it by yourself: identify slow parts, make these parts based on server components, and use a streaming approach for them. There will be no magic thing that will boost your performance, but you will get more granular control over the performance of your website.

And, indeed, all approaches show decent performance scores. The difference is minimal. And even if you utilize use client everywhere, for the whole of your website, like it is with Sitecore JSS PoC, you still will get a good performance score! You should not be afraid use client directives. And if you need it, then use it without a doubt. It will not ruin your website performance.