Front-End Web & Mobile

SSG vs SSR in Next.js Web Applications: Choosing the Right Rendering Approach

Next.js, a popular React framework, has changed the way developers build modern web applications. It offers powerful features, such as Server-Side Rendering (SSR) and Static Site Generation (SSG), which optimize your application’s performance and user experience. In this blog post, we’ll explore the key differences between SSG and SSR, their advantages, when to choose one over the other, and how to deploy either approach using AWS Amplify. Amplify is a complete solution that lets frontend web and mobile developers easily build, ship, and host full-stack applications on AWS.

What is Static Site Generation (SSG)?

Static Site Generation, as the name suggests, generates static HTML files during the build time. Every time you build an app, a bunch of pages are created. These files are then served to users, which means the server doesn’t need to do any extra work when a user visits the website. This approach is ideal for websites with content that doesn’t change frequently, like blogs or documentation sites.

Advantages of SSG

  • Speed: Pre-rendered HTML files are served directly, resulting in faster load times.
  • Scalability: Static files can be easily served by Content Delivery Networks (CDNs), improving your application’s ability to handle more global traffic around the world.

What is Server-Side Rendering (SSR)?

Server-Side Rendering involves generating the HTML for each page on the server when a user requests it. With SSR, there is a server that pre-renders the page – it’s like a template that you plug variables into and the server handles all of the rendering. This happens at request time, so when the user requests the page, they get the server side rendered page. This rendering happens all on the server side and never runs in the browser. So, unlike SSG where the page is already rendered in the server waiting to be served to the client, SSR renders the page on the server upon receiving a request. SSR is ideal for websites with dynamic or personalized content that changes frequently, like e-commerce websites or social media platforms.

Advantages of SSR

  • Consistent user experience: Users see the latest content as it’s generated on-the-fly, ensuring they always have up-to-date information.
  • Personalization: SSR allows you to serve unique content based on user preferences or other dynamic data.

When to Choose SSG or SSR

  • Is your content updated frequently?  If your content doesn’t change often, SSG is the better choice for improved performance and scalability. For dynamic content, SSR ensures users see the most up-to-date information.
  • Does your website provide an interactive user experience?  SSR websites provide an interactive user experience, whereas SSG websites are largely static sites with little to no dynamic content, unless your site is combined with CSR or SSR.
  • Do you want to incur the rendering cost at build-time or run-time?  Choose SSG if you want to incur the rendering cost at build-time and SSR for run-time.
  • Do you have an SEO requirement?  The primary difference between SSR and SSG for SEO is only the server response time.

Consider your Business Requirements

While SSG provides excellent SEO benefits, SSR offers better support for dynamic content and personalization that may be crucial for search rankings.

  • User Experience: Consider whether your users need real-time data or personalized content. If so, SSR is the better option. Otherwise, SSG offers a faster experience with lower server requirements.
  • Latest Data: SSR pages will always display the latest data because they are generated on the server with every request from the user. With every request, you can always be sure that you have the most recent/up-to-date information.

SSG vs SSR in Next.js: Choosing the Right Rendering Approach

In this article, we will discuss the two rendering approaches in Next.js: SSG and SSR. We will also provide an example codebase that will help you determine the best rendering approach for your application.

Next.js supports the ability to generate an “n” number of dynamic generated routes. In our example codebase, we fetch 100 of the top Hacker News posts in the last few days and render those IDs onto the home page.

When clicked, each of those pages reveal the details of the post. Each of those pages will also have the route like “pages/[hackerNewsArticleId]”. You can see how that template page is available on the pages folder with the [slug] designation.

Now, you may be asking how do we define this list of paths to be statically generated? We will use two NextJS functions: getStaticProps and getStaticPaths.

getStaticProps will pre-render the page at build time, fetch from the Hacker News API the list of posts information, and pass that information into the props of our component as well as getStaticPaths.

Our second function, getStaticPaths, is the key to dynamic routing. It will receive the list of IDs from getStaticProps and create a list of path objects like this:

export async function getStaticPaths() { 
       return { 
             paths: [{ params: { id: '1' } }, { params: { id: '2' } }], 
             fallback: false, // can also be true or 'blocking' 
      } }

Next.JS will now ingest this list of paths and generate a new page for each of those params. We have also now allowed the primary component ingest the Hacker News IDs to render for routing to the individual page. If you go to our dynamically rendered component page, you will see that we again call the getStaticProps method to call the Hacker News details endpoint to fetch the post’s title, votes, etc. Notice that this is a snapshot of the blog post at the time of compilation.

SSG Approach

We will go over deploying a SSG Next.js app from this Github repository to Amplify. To start off, click below to deploy this project in your own environment. Here is more information about deploying and hosting with Amplify.

Deploy to Amplify

Select Connect to GitHub and authorize aws-amplify-console.

Screenshot of connecting your GitHub repo to Amplify

On the Deploy App page, go ahead and select Create new role, leaving all of the defaults for your Amplify backend role.

Screenshot of deploying your Github repo to Amplify

Once you’ve created the role, refresh the existing roles back on the Deploy App page and select the role you just created. Select Save and Deploy.

Deploying your app will take 2-3 minutes. Click Continue when the box appears. Then, you can monitor as your Amplify app goes into the provision, build, and deploy phases.

Screenshot of deploying your Amplify app

Once it has finished deploying, you’ll be able to visit the website hosted under the Domain.

Screenshot once your Amplify app has been deployed

When you select your domain, you’ll be navigated to your Amplify app which will display your SSG Next.js app.

SSR Approach

We will look how we can deploy a NextJS web application from GitHub directly to Amplify.

Surprise! We actually already deployed a SSR page when we deployed to Amplify. The amazing thing about Next.JS is that you can have some pages be generated at build time, while other pages can still render dynamic data by leveraging SSR.

To use Server-side Rendering for a particular page, we export an async function called getServerSideProps. This function will be called by the server on every request.

Now, on your hosted link, navigate to the /ssr route (ie. https://main.<YOUR_ENDPOINT>.amplifyapp.com/ssr). Now, you should see a page like this:

Your SSR Next.js app

Common Gotchas

Next.js requires a different paradigm shift away from the very popular frontend frameworks leveraging the libraries of Create React App (CRA) and React Router.

CRA is a starter kit that provides you with a boilerplate project for creating a React application. CRA uses client-side rendering (CSR), which means that your application is rendered in the browser, and typically it is best practice to break up your network requests based on user’s interactions. In comparison to SSG, you now have to load all the data all at once.

By including these Common Gotcha section, we hope you can learn from our mistakes and save some time and frustration.

  • Server Side Generation
    • Instead of passing along all of the build and data fetching time to the customer, you might be stuck hours waiting for your site to build because you have a large scale static website. Every time, you double the number of static pages, you are doubling the build time duration.
      • If you have an e-commerce website with 10,000 items, each taking about 1 second to fetch/build, you are looking at nearly 3 hours of building and deployment.
      • In this example, you could go the incremental static regeneration pathway, where you can create and update pages after you’ve built your primary website bundle. This allows you to make changes without rebuilding the entire website.
    • Data Fetching
      • In modern web development, it is often recommended that users make API calls only enough to fill the user’s viewport and potentially prefetch data for subsequent user actions. However, with SSG, you will need to call all the APIs necessary to populate the entire webpage and all potential user’s actions.
    • Page updates
      • If you have a frequent update to a page on your website, for example, a Blog page that has multiple sections; SSG might cause you to rebuild the entire site very frequently for changes that are contained in a single page.
      • The pages are generated before the requests are made, as a result, SSG pages don’t have direct access to requests like HTTP headers and query parameters at build time. If you want to access these, you have to write custom middleware in addition to SSG.
  • Server-Side Rendering
    • Latency
      • During the generation process, there are external factors that can ultimately influence page loading speed like fetching data from external APIs. If the APIs are slow to respond, page generation loading times will be slower. Also, because SSR generates each page per request, this made it slower compared to SSG.
      • To enable caching with SSR pages and improve the loading times (speed), you will need to add an additional HTTP header , Cache-Control, when calling “getServerSideProps”. See the docs here. Learn more about caching.
    • Scalability
      • SSR requires server to process and generate the front-end on each request, which is less scalable and slower; provided the website have complex pages and a lot of end clients to process.
      • SSR dynamic HTML cannot be cached by static CDNs (Content Delivery Network, e.g. CloudFront), which would lead to longer trips to and from the server, and a slower time between requesting a page and the first byte loaded by a server (TTFB: Time to First Byte).
    • SEO
      • Although Google and Bing announced they leverage the same Chromium based crawlers with the latest rendering engine, Javascript still complicates the search engine’s ability to parse your page and potentially lower your SEO rank. Search engines must download your Javascript files, and potentially not wait for the entire bundle to load before moving onto to other parts of your site. At the end of the day, there is a lot of uncertainty at guessing how Google or Bing ranks your page, and it potentially makes sense to make the crawler’s life easier.

Cleaning Up

Conclusion

Both SSG and SSR offer unique advantages for different types of Next.js applications. By understanding your project’s content frequency, SEO requirements, user experience, and development complexity, you can make an informed decision about whether to use SSG or SSR in your Next.js project. Ultimately, the choice depends on your specific use case and the trade-offs you’re willing to make between performance, scalability, and dynamic content.

To get started, try your hand at building a Next.js 13 web app with user authentication using Amplify Hosting.

Alexa Bio

Alexa Perlov

Alexa Perlov is a Solutions Architect at Amazon Web Services, based in New York City. She supports Media and Entertainment strategic accounts in utilizing AWS to achieve their business goals. She leads technical trainings and develops prototypes, highlighting a wide range of cloud domains.

Alexa Bio

Michael Tran

Michael Tran is a Solutions Architect with Prototyping Acceleration team at Amazon Web Services. He provides technical guidance and helps customers innovate by showing the art of the possible on AWS. He specializes in building prototypes in the AI/ML space. You can contact him @Mike_Trann on Twitter.