Static site generators are very suitable for blog posts, developer documentation or marketing pages, and JAMstack becomes a recent buzzword. For this website I prefer Node.js for the build process, Markdown or MDX as content container, and React for the presentational layer.
Frameworks for Static Generation
I have been happy with Vue until last year when I used it for server side rendering in a project. I came across a couple of issues that I couldn't find an answer with search engines. I ended up rewriting the development server logic and the webpack configs from the official demo vue-hackernews-2.0. The same questions, however, can be answered in React. An active developer community matters a lot when choosing a framework, because it is more likely to find a solution there when problem arises.
I am not using server side rendering for this site. Instead, static contents are generated in advance. Since the static rendering at build time is almost identical to the phase of generating static HTML in server side rendering, I want to try something new outside the Vue ecosystem. React seems to have a more mature ecosystem, and it makes sense to consider React in this scenario.
Gatsby.js or Next.js ?
In the React's ecosystem, both Gatsby and NextJS can generate static contents. However, there are differences between them. Gatsby claims that it is doing a better job in image optimization, accessibility and data sourcing.
Gatsby is a static site generator (SSG) in the first place, but it never stops you from having dynamic contents via client-side rehydration with React. With Gatsby you can always create hybrid pages that fetch static data at build time and load dynamic data in client-side runtime. However, there is a catch you need to be careful with. The routes created in the build process and the routing in browser can be different. Gatsby uses @reach-router, not the popular browser-oriented @react-router-dom for navigation. The navigation links created in Gatsby correspond to the static files in the
NextJS focuses on the server side rendering (SSR) from the beginning and that's what it is most famous for. It is catching up with static generation recently. The support for static html export at build time has been introduced since v3 (2017.05). In a server runtime environment, automatic static optimization is enabled by default in v9.3+ (released in 2020.03) and stable incremental static regeneration has been added into the picture in v9.5+ (released in 2020.07). NextJS uses file-system based routing for navigation between pages, and has a separate API next/link exclusive for the client-side navigation.
Static files can be generated with or without data. However, the strategy and timing of data fetching makes a big difference. Gatsby primarily relies on GraphQL to source data in build time. NextJS allows data fetching both in build time and runtime, and permits periodic updates of data in the background.
Gatsby ships GraphQL out of the box for data sourcing. Although it is possible to use Gatsby without GraphQL, GraphQL is recommended as the data layer in official tutorials and documentation. Gatsby claims superiority in data sourcing. The integration of GraphQL in the build process, together with a rich plugins ecosystem, contributes the popularity of Gatsby. With source plugins and transformer plugins, you can fetch and process data from local file systems, APIs, CMS and databases. Data are modelled as nodes objects in Gatsby and exposed with explicit or inferred types to GraphQL in the bootstrap phase. In the build phase, Gatsby runs queries from components and pages, loads JSON data from GraphQL, and merges the data with components and pages to create static HTML files. The heavy lifting of fetching and structuring data through GraphQL has been done internally in Gatsby. It becomes an one-stop solution to those who want to migrate from traditional CMS-based platforms to a more cost-efficient static hosting services.
NextJS has more flexibility in general and is suitable for SSR or a hybrid of SSR with static generation. If you are building an e-commerce site with 100,000+ products, a full rebuild is slow and unrealistic when update gets frequent. This e-commerce example adopts static generation for pages or parts of the pages that look the same to all users and rarely change between requests. For existing pages that are pre-rendered with data and may change at some point, fetching data and partial rebuild can be scheduled periodically in the background. It is called incremental static (re)generation and can be achieved with the
revalidate APIs. For user-specific contents where SEO doesn't matter, they can be statically generated without data ahead of time and rely on client-side data fetching like most SPA. Static generation is designed to offload pressure on the backend.
Both Gatsby and NextJS are capable of building static websites. Powered by GraphQL, Gatsby has some edges in data sourcing and the plugins ecosystem. The limitation is that it doesn't scale well as a website grows to a point when update becomes frequent, and the build time increases with the size of bundles. To mitigate the problem, the incremental builds feature was introduced in Gatsby v2.20.4. It was initially only accessible in Gatsby Cloud (2020.04), but became available in the open-source version of Gatsby v3+ (2021.03).
Leveraging the power of incremental static generation, NextJS is a good fit for creating and updating websites large and small. The flexibility also means less overhead. Not everyone needs GraphQL as data layer for static pages. Static files can be generated without data after all. Decoupling static generation from data source is sustainable in the long run. Although NextJS doesn't have a rich plugins ecosystem comparable to Gatsby, you will probably like it for its pristine structure and easy-to-follow documentation.