The Genius of NextJS and Gatsby as React Static Site Generators

Check out our starter sites for both NextJS and Gatsby

Joel Varty
Joel Varty
Aug 21, 2020

At Agility CMS we've chosen to create starter sites for both NextJS and Gatsby. Both are static site generators built on top of React, but they take a very different approach to how they actually generate the static html/js/css for a website.


Or do they?

1 | A starter NextJS website using Agility CMS, Tailwinds CSS, and several pre-built components

GitHub logo agility / agilitycms-nextjs-starter-2020

Live website demo

2 | A sample GatsbyJS website using the Agility CMS Gatsby source plugin

They both actually do one thing in a very similar way, and I think it's just genius: they give you a "hook" to specify the JSON data that will be used to generate the output for the site. This ends up being the "props" variable that gets passed to your React components. This data is used both during the build process on the server and also ON THE CLIENT SIDE.

That's right - your React code is executed during BUILD time and also in the BROWSER, so the execution of your code can happen in 2 different contexts. That's a little weird, at first, but if you're smart about it, you can make this work for you.

First of all, having that JSON data available is what makes NextJS and Gatsby pretty magical. It means that, as a framework on top of React, they can route pages after the first page-load without doing a full page reload - all that's needed is that extra JSON and whatever extra dependencies are on the new page.

If you need to export JSON data eventually, you can do it easily using available data integration tools. For example, you can load JSON data to BigQuery and use it for further analytics purposes

You can see this on pretty much any Gatsby or NextJS site - if the developers have used the <Link> component correctly.

One area where I saw a huge performance improvement was on a listing page. Check out the blog listing page here: https://agilitycms.com/resources/posts

Originally, this page was rendered on the front-end using this module: which had to do calls back to the server every time more posts needed to be loaded.

loadMore(skip, take) {

        var url = `/Listing/Posts?skip=${skip}&take=${take}`

        fetch(url)
            .then(response => response.json())
            .then(data => {

                let noMore = false;
                if (!data.posts || !data.posts.length || data.posts.length == 0) {
                    noMore = true;
                }

                this.setState(prevState => ({
                    posts: prevState.posts.concat(data.posts),
                    loadingMore: false,
                    skip: data.skip,
                    take: data.take,
                    noMoreData: noMore
                }));


            }).catch(err => {
                console.warn("An error occurred while loading more data...", err);
                this.setState(prevState => ({
                    loadingMore: false,
                    noMoreData: true
                }));
            });

        return false;
    }

Gatsby

With Gatsby, we were able to get all the data we needed for loading posts at BUILD time with a <StaticQuery> and then use an <InfiniteScroll> component to render that on the client-side.

The big win here? No calls back to the server!

Here's the main component that loads the list of posts: https://github.com/agility/agility-website-gatsby/blob/master/src/modules/PostListing.js

export default props => (
    <StaticQuery
        query={graphql`
        query PostListingQuery {
            allAgilityBlogPost(filter: {properties: {referenceName: {eq: "blogposts"}}}, sort: {fields: customFields___date, order: DESC}) {
              nodes {
                contentID
                customFields {
                  date(formatString: "MMMM D, YYYY")
                  excerpt
                  title
                  uRL
                  postImage {
                    url
                    label
                  }
                }

              }
            }
          }
        `}
        render={queryData => {

            let posts = queryData.allAgilityBlogPost.nodes;

            const viewModel = {
                item: props.item,
                posts: posts
            }
            return (
                <ReusablePostListing {...viewModel} />
            );
        }}
    />
)

Here's the reusable component that actually renders out the posts with the InfiniteScroll component: https://github.com/agility/agility-website-gatsby/blob/master/src/components/reusable-post-listing.jsx

loadMorePosts(skip, take) {

        let noMore = false;

        let thesePosts = [];
        if (skip >= this.allPosts.length) {
            noMore = true;
        } else {
            thesePosts = this.allPosts.slice(skip, skip + take)
        }

        this.setState(prevState => ({
            posts: prevState.posts.concat(thesePosts),
            loadingMore: false,
            skip: skip,
            noMoreData: noMore
        }));        
    }

NextJS

The same logic holds for NextJS websites built with Agility CMS.

Check out this Post Listing example from the starter site. https://github.com/agility/agilitycms-nextjs-starter-2020/blob/master/components/agility-modules/PostsListing.js

While Gatsby has a component that renders data from GraphQL, the Agility CMS NextJS project uses a "getCustomInitialProps" method that allows you to do any data fetches at BUILD time, and then NextJS provides that JSON data to the component at render time and on the client for use.

PostsListing.getCustomInitialProps = async function ({agility, channelName, languageCode}) {
    const api = agility;

    //get our posts
    let rawPosts = await api.getContentList({ referenceName: 'posts', languageCode });

    return {
        posts
    }
}

Note the use of the component in both examples.

This is all made possible by 2 amazing static site generation frameworks that are making it easier to make a faster web.


Get Started Now

Get started on a free Agility CMS account today to test out Gatsby or NextJS with starter solutions pre-configured and ready to go. Sign up here.

Back to All Articles
Back to All Articles
Aug 21, 2020

The Genius of NextJS and Gatsby as React Static Site Generators

Check out our starter sites for both NextJS and Gatsby

Joel Varty

At Agility CMS we've chosen to create starter sites for both NextJS and Gatsby. Both are static site generators built on top of React, but they take a very different approach to how they actually generate the static html/js/css for a website.


Or do they?

1 | A starter NextJS website using Agility CMS, Tailwinds CSS, and several pre-built components

GitHub logo agility / agilitycms-nextjs-starter-2020

Live website demo

2 | A sample GatsbyJS website using the Agility CMS Gatsby source plugin

They both actually do one thing in a very similar way, and I think it's just genius: they give you a "hook" to specify the JSON data that will be used to generate the output for the site. This ends up being the "props" variable that gets passed to your React components. This data is used both during the build process on the server and also ON THE CLIENT SIDE.

That's right - your React code is executed during BUILD time and also in the BROWSER, so the execution of your code can happen in 2 different contexts. That's a little weird, at first, but if you're smart about it, you can make this work for you.

First of all, having that JSON data available is what makes NextJS and Gatsby pretty magical. It means that, as a framework on top of React, they can route pages after the first page-load without doing a full page reload - all that's needed is that extra JSON and whatever extra dependencies are on the new page.

If you need to export JSON data eventually, you can do it easily using available data integration tools. For example, you can load JSON data to BigQuery and use it for further analytics purposes

You can see this on pretty much any Gatsby or NextJS site - if the developers have used the <Link> component correctly.

One area where I saw a huge performance improvement was on a listing page. Check out the blog listing page here: https://agilitycms.com/resources/posts

Originally, this page was rendered on the front-end using this module: which had to do calls back to the server every time more posts needed to be loaded.

loadMore(skip, take) {

        var url = `/Listing/Posts?skip=${skip}&take=${take}`

        fetch(url)
            .then(response => response.json())
            .then(data => {

                let noMore = false;
                if (!data.posts || !data.posts.length || data.posts.length == 0) {
                    noMore = true;
                }

                this.setState(prevState => ({
                    posts: prevState.posts.concat(data.posts),
                    loadingMore: false,
                    skip: data.skip,
                    take: data.take,
                    noMoreData: noMore
                }));


            }).catch(err => {
                console.warn("An error occurred while loading more data...", err);
                this.setState(prevState => ({
                    loadingMore: false,
                    noMoreData: true
                }));
            });

        return false;
    }

Gatsby

With Gatsby, we were able to get all the data we needed for loading posts at BUILD time with a <StaticQuery> and then use an <InfiniteScroll> component to render that on the client-side.

The big win here? No calls back to the server!

Here's the main component that loads the list of posts: https://github.com/agility/agility-website-gatsby/blob/master/src/modules/PostListing.js

export default props => (
    <StaticQuery
        query={graphql`
        query PostListingQuery {
            allAgilityBlogPost(filter: {properties: {referenceName: {eq: "blogposts"}}}, sort: {fields: customFields___date, order: DESC}) {
              nodes {
                contentID
                customFields {
                  date(formatString: "MMMM D, YYYY")
                  excerpt
                  title
                  uRL
                  postImage {
                    url
                    label
                  }
                }

              }
            }
          }
        `}
        render={queryData => {

            let posts = queryData.allAgilityBlogPost.nodes;

            const viewModel = {
                item: props.item,
                posts: posts
            }
            return (
                <ReusablePostListing {...viewModel} />
            );
        }}
    />
)

Here's the reusable component that actually renders out the posts with the InfiniteScroll component: https://github.com/agility/agility-website-gatsby/blob/master/src/components/reusable-post-listing.jsx

loadMorePosts(skip, take) {

        let noMore = false;

        let thesePosts = [];
        if (skip >= this.allPosts.length) {
            noMore = true;
        } else {
            thesePosts = this.allPosts.slice(skip, skip + take)
        }

        this.setState(prevState => ({
            posts: prevState.posts.concat(thesePosts),
            loadingMore: false,
            skip: skip,
            noMoreData: noMore
        }));        
    }

NextJS

The same logic holds for NextJS websites built with Agility CMS.

Check out this Post Listing example from the starter site. https://github.com/agility/agilitycms-nextjs-starter-2020/blob/master/components/agility-modules/PostsListing.js

While Gatsby has a component that renders data from GraphQL, the Agility CMS NextJS project uses a "getCustomInitialProps" method that allows you to do any data fetches at BUILD time, and then NextJS provides that JSON data to the component at render time and on the client for use.

PostsListing.getCustomInitialProps = async function ({agility, channelName, languageCode}) {
    const api = agility;

    //get our posts
    let rawPosts = await api.getContentList({ referenceName: 'posts', languageCode });

    return {
        posts
    }
}

Note the use of the component in both examples.

This is all made possible by 2 amazing static site generation frameworks that are making it easier to make a faster web.


Get Started Now

Get started on a free Agility CMS account today to test out Gatsby or NextJS with starter solutions pre-configured and ready to go. Sign up here.

About the Author

Joel is CTO at Agility. His first job, though, is as a father to 2 amazing humans.

Joining Agility in 2005, he has over 20 years of experience in software development and product management. He embraced cloud technology as a groundbreaking concept over a decade ago, and he continues to help customers adopt new technology with hybrid frameworks and the Jamstack. He holds a degree from The University of Guelph in English and Computer Science. He's led Agility CMS to many awards and accolades during his tenure such as being named the Best Cloud CMS by CMS Critic, as a leader on G2.com for Headless CMS, and a leader in Customer Experience on Gartner Peer Insights.

As CTO, Joel oversees the Product team, as well as working closely with the Growth and Customer Success teams. When he's not kicking butt with Agility, Joel coaches high-school football and directs musical theatre. Learn more about Joel HERE.

Take the next steps

We're ready when you are. Get started today, and choose the best learning path for you with Agility CMS.

Get startedRequest a Demo