TABLE OF CONTENTS

How To Use Next.js as a Static Site Generator

Static Site Generators (SSG) are becoming extremely popular in the world of web development and Next.js is a proud competitor in this race.

It enables Next js developers to build superfast and super SEO friendly websites, without compromising the quality, and the freedom of User Experience execution.

Let’s have a closer look at the nature of static pages and see how they can elevate websites’ overall user experience and performance.

What are Static Site Generators?

A Static Site Generator (SSG) is a tool that generates a complete static HTML website based on raw data and templates. It’s known for delivering super-fast websites because it generates pages at build time.

Next.js is considered a great option for SSG because it not only generates static pages but also provides benefits like super-fast performance, enhanced security, and improved user experience without compromising on SEO or the quality of the user interface.

🚀 STATIC = BLAZINGLY FAST 🚀

Static Site Generator is extremely fast. Once loaded, they prefetch resources for other pages so clicking around the site feels like a blink of an eye.

💎 STATIC = SAFE 💎

With a static site generator, you will just publish static files, which means there is no direct connection to the database, dependencies, user data or other sensitive information.

😎 STATIC = ENHANCED USER EXPERIENCE 😎

Simply because clicking and walking through your website feel like a walk in a park on a sunny day with no unexpected turns, stairs, or dead ends.

Static Pages got also kind of a new brand name on the market, which is Jamstack.

What is Next.js?

“Next is a framework which we can use to build React sites with Server Side Rendering or generate static pages from our react code. All that configured for us by Next itself.”

And in this post, we will be taking a look at the static pages export functionality and how we can make it with next.js.

Let’s go!

Creating an app

We will start by creating a new next app. To do that simply run the command:

yarn create next-app
# or if you are using npm
npx create-next-app

Now, let’s take a look at our project structure:

next app structure

pages – this directory contains all our pages and defines routing for our app (more about routing here).

pages/api – here we can add our API endpoint if we need some, in our case we can remove this folder safely (more about API routes here).

public – we can put all our static assets in this directory.

Let’s change our commands to reflect what we want to achieve in this project. Got to package.json and modify scripts section like this:

"dev": "next dev" -> # remove
"build": "next build" -> "build": "next build && next export"
"start": "next start" -> "start": "next dev"

So now our scripts section should look like this:

{
  ...
  "scripts": {
    "build": "next build && next export",
    "start": "next dev"
  },
  ...
}

Now we can test our configuration, run the build command:

yarn run build
# or if you are using npm
npm run build

Next should create out the directory at the root of our project with all the static HTML files and assets ready to host. We can change the out directory by adding a -o flag to our next export command like this:

{
  ...
  "scripts": {
    "build": "next build && next export -o build",
    ...
  },
  ...
}

Still not sure if Next.js is for you?

Adding content to page

Let’s head to pages\index.js file and remove the content of Home component and change it like this:

const Home = () => {
  return (
    <p>
      Hello From my next.js app!
    </p>
  )
}

export default Home;

And start our app by running command:

yarn run build
# or if you are using npm
npm run build

Now you should be able to access http://localhost:3000 and see our Home component content.

Now let’s add some content that will be evaluated at the build time. We can do that by using getStaticProps which is a function exported from our page. As we don’t have any data source configured yet we will do a simple example to show how getStaticProps work.

const Home = ({ buildTimestamp }) => {
  return (
    <p>
      Hello From my next.js app!
      App built at: {buildTimestamp}
    </p>
  )
}

export const getStaticProps = () => {
  return {
    props: {
      buildTimestamp: Date.now()
    }
  }
}

export default Home;

We will see that buildTimestamp changes every refresh, this will not be the case when we build our app because getStaticProps is called only once when app is building.

Adding data source

We already know how getStaticProps works, now we can make it more useful and add some external data sources to our app. Next.js doesn’t come with any data provider built in (for example GatsbyJS has graphql) so we will have to add it manually.

Basically you can load your data however you like. In this tutorial we will use GraphQL with Apollo Client. First, let’s add src directory where we will keep all our code shared between pages. Then create src\setup\apolloClient.js file where our apollo client will be created.

import { ApolloClient, InMemoryCache } from "@apollo/client"

const apolloClient = new ApolloClient({
  uri: "https://gitlab.com/api/graphql",
  cache: new InMemoryCache()
})

export default apolloClient

Additionally, we will have to install some apollo related packages. Simply run the command:

yarn run add @apollo/client graphql
# or if you are using npm
npm install --save @apollo/client graphql

As you can see we will be using GitLab graphql api (explorer is available here).

Creating pages and fetching data

Now we can fetch some data, let’s fetch some repositories. First we have to create graphql query:

const PROJECTS_QUERY = gql`
  query {
    projects (first: 10) {
      nodes {
        id
        name
        description
      }
    }
  }
`

Now we can import apollo client and use it with above query in our getStaticProps:

export const getStaticProps = async () => {
  const { data } = await apolloClient.query({
    query: PROJECTS_QUERY
  })

  return {
    props: {
      projects: data.projects
    }
  }
}

Now list of GitLab projects is available in our Home component props, let’s render it.

const Home = ({ projects }) => {
  return (
    <ul>
      {projects.nodes.map(({ name, description, id }) => (
        <li key={id}>
          <p><strong>{name}</strong></p>
          {description && <span>{description}</span>}
        </li>
      ))}
    </ul> 
  )
}

And that’s it, we have a working GitLab projects list.

Now let’s add project detail page.

First, we have to add a dynamic route to our app, we can do that by creating a file with square brackets in its name, like this:

a square presenting how to save a project with square brackets

More about dynamic routing here.

When we are building our pages statically Next.js requires us to export a function called getStaticPaths from our page.

We have to do that because Next.js needs to know all the page URLs and their params at the build time. We have fetched the first 10 Gitlab projects at our homepage so now we have to do the same in our getStaticPaths to generate URLs.

First, let’s add links to projects details on the homepage. We have to add fullPath field to our query:

const PROJECTS_QUERY = gql`
  query {
    projects (first: 10) {
      nodes {
        id
        name
        description
        fullPath
      }
    }
  }
`

And render next link for every project:

const Home = ({ projects }) => {
  return (
    <ul>
      {projects.nodes.map(({ name, description, id, fullPath }) => (
        <li key={id}>
          <p><strong>{name}</strong></p>
          {description && <span>{description}</span>}
          <div>
            <Link href={`/project/${fullPath}`}>
              Details
            </Link>
          </div>
        </li>
      ))}
    </ul>
  )
}

Now we can add code to our project details page:

import gql from "graphql-tag";
import apolloClient from "../../src/setup/apolloClient";

const ProjectDetailsPage = ({ fullPath }) => {
  return <>Project details page {fullPath}</>
}

export default ProjectDetailsPage;

const PROJECTS_QUERY = gql`
  query {
    projects(first: 10) {
      nodes {
        fullPath
      }
    }
  }
`

export const getStaticPaths = async () => {
  const { data } = await apolloClient.query({
    query: PROJECTS_QUERY,
  })

  return {
    paths: data.projects.nodes.map(({ fullPath }) => ({ // 1
      params: { fullPath: fullPath.split('/') },
    })),
    fallback: false, // 2
  }
}

export const getStaticProps = ({ params }) => {
  return {
    props: {
      fullPath: params.fullPath.join('/') // 3
    },
  }
}

Let’s explain some key parts here:

  1. We map our projects list to an array of paths required by Next.js. Structure that Nexts.js expects looks like this:
{
  paths: [
    {
       params: {
         (all params that we want to pass to getStaticProps)
       }
    }
  ]
}

Also when we use Catch All route we have to pass our param as array that’s why we use split here.

  1. We have to tell next if we want to render missing pages live or just return 404. In our case we are making fully static page so we define fallback as false. More about fallback here.
  2. We merge our fullPath param to single string so we can display it nicely in our component.

Now we can change getStaticProps to be more useful and fetch some project data for us. First we need query for project details:

const PROJECT_DETAILS_QUERY = gql`
  query ($fullPath: ID!) {
    project(fullPath: $fullPath) {
      name
      descriptionHtml
      repository {
        empty
        tree {
          lastCommit {
            sha
          }
        }
      }
    }
  }
`

And run it inside of our getStaticProps

export const getStaticProps = async ({ params }) => {
  const fullPath = params.fullPath.join('/');
  const { data } = await apolloClient.query({
    query: PROJECT_DETAILS_QUERY,
    variables: {
      fullPath
    }
  })

  return {
    props: {
      project: data.project
    }
  }
}

Now we can display some data on our project details page:

const ProjectDetailsPage = ({ project }) => {
  const {
    name,
    descriptionHtml,
    repository: {
      tree
    }
  } = project
  const { lastCommit } = tree || {}
  const { sha } = lastCommit || {}

  return (
    <div>
      <h1>{name}</h1>
      <p dangerouslySetInnerHTML={{ __html: descriptionHtml }} />
      {sha && <p>Last commit SHA: {sha}</p>}
    </div>
  )
}

And that’s it, we have created a static page displaying first 10 GitLab projects and their details.

We can now build it and serve to check if everything is working properly.

yarn run build
# or if you are using npm
npm run build

# if you are using yarn and don't have serve installed run this command first
yarn global add serve


# if you are using yarn
serve ./build
# or if you are using npm
npx serve ./build

Access the full project here.

Next.js and Jamstack

Jamstack is extremely hot lately, as it’s an architecture (or now even a philosophy) that is entirely focused on building superfast and extremely SEO-friendly websites.

And there’s no surprise that Next.js became one of the best Jamstack development frameworks to use nowadays.

If you are more of a business person, or you search for a clear explanation of Jamstack, we’ve made a Jamstack guide for business people called “What is Jamstack?” which will probably answer all the questions that could come to your mind regarding this modern approach.

Maybe the Jamstack approach could be good in your case as well? In this video, we help you decide when is best to use Jamstack, and when not:

youtube video about when to use and when not to use jamstack

Next.js vs GatsbyJS

As we can see Next.js can successfully generate static pages like GatsbyJS does and someone could ask:

“Can Next.js replace GatsbyJS?”

a cartoon pirate is saying you cannot actually replace GatsbyJS with Next.JS

You can do all the things in Next.js that you do in GatsbyJS but it takes much more time because you need to do everything by yourself.

GatsbyJS has a lot of plugins that help to solve many problems and optimize the page. More than that it has data fetching features built in (graphql available out of the box). So for now we will have to wait for Next.js ecosystem to grow and get more plugins so we can create static pages as fast as we do in GatsbyJS.

Keep in mind that Next.js has one big advantage over GatsbyJS:

  • you can create and app which is partially static and dynamic.

For example, you can prerender the first 10 posts from your blog and the rest can be rendered when the page is requested by the user.

So for now Next.js is just a more flexible solution that requires more work and gives us some powerful extra features but in terms of development time, GatsbyJS is still better.

You can also watch a video about the most important changes between Gatsby and Next.js in my friend’s video below:

youtube video about the differences between gatsby vs nextjs

Next.js vs React (CRA)

We’ve also made a comparison between Next.js and plain React, or Create-React-App (CRA) in other words.

youtube video about the differences between nextjs and create react app (cra)

FAQ

Can Next.js integrate with data sources, and how can it fetch data at build time?

Yes, Next.js can integrate with various data sources. For fetching data at build time, Next.js offers a function called getStaticProps. This function allows you to fetch data and pass it as props to your page at build time. Although Next.js doesn’t come with a built-in data provider, you can easily integrate it with external data sources like GraphQL with Apollo Client or any other API of your choice.

What makes Next.js a preferred choice for static site generation in 2024?

Next.js continues to be a popular choice for static site generation due to its speed, performance, and SEO benefits. It offers exceptional speed through static generation and optimized code, which reduces bounce rates and improves SEO rankings. Additionally, its ecosystem is rich, supported by Vercel and Meta, ensuring a future-proof and scalable solution for web development. Regular updates and a vibrant community contribute to its strategic advantage for tech leaders.

How does Next.js compare to other static site generators like Astro or Eleventy in 2024?

Next.js is characterised by its flexibility in offering multiple rendering methods, including SSG, SSR, Incremental Static Regeneration, and Client-Side Rendering, making it suitable for complex projects.

In contrast, Astro is highlighted for its content-driven approach and ease of use without requiring knowledge of specific frameworks like React or Vue. Eleventy is praised for its simplicity and flexibility, being framework-agnostic and offering a straightforward setup for projects of various complexities

Read more

Pros and cons of Next js

Next js vs Gatsby

18 Great examples of Next js websites

How to rank higher on Google with Next js

Article link copied

Close button

Leave a Reply

* Required informations.