Creating Dynamic Content and Client-Only Routes in GatsbyJS [Part 8]

In this article of our GatsbyJS series, we delve into dynamic content and client-only routes. Building on the knowledge gained from our previous articles, we’ll explore how to add interactivity using React state and hooks, create client-only routes, and implement user authentication. These features empower developers to craft engaging and interactive web applications using GatsbyJS.

Let’s dive in!

Different Rendering Methods in Gatsby

Gatsby offers multiple rendering methods to suit various use cases and performance requirements. These rendering methods determine how content is loaded and displayed in your web application. The primary rendering methods in Gatsby are –

Server-Side Rendering (SSR)

In SSR, the server renders the initial HTML content and sends it to the client. This approach benefits search engine optimization (SEO) and initial page load speed. Gatsby’s SSR capabilities allow you to pre-render dynamic data on the server before delivering the page to the user’s browser.

Static Site Generation (SSG)

SSG generates static HTML files during build time. This results in faster page loads and reduced server load. Gatsby excels at SSG by generating optimized static assets that can be cached and served globally, providing a smooth browsing experience for users.

Dynamic Site Generation (DSG)

DSG is a hybrid approach that combines the benefits of SSR and SSG. It generates dynamic content during build time for specific pages while allowing client-side rendering for other application parts. This strikes a balance between SEO optimization and interactivity.

Client-Side Rendering (CSR)

Gatsby Partial hydration

CSR loads the initial HTML content and JavaScript bundle, and the client’s browser takes over, rendering subsequent content changes. This method offers dynamic content updates without a full page reload, enhancing user interactivity.

Advantages of Using Client-Side Rendering

Client-side rendering, while not suitable for all scenarios, offers several advantages:

Interactive User Experience

CSR enables smooth and interactive user experiences by updating content dynamically without full page reloads. This is ideal for applications with real-time updates or frequent user interactions.

Faster Initial Page Load

Initial page load is faster in CSR compared to SSR, as the server sends a minimal HTML structure along with JavaScript assets. This can lead to quicker perceived performance.

Reduced Server Load

With CSR, the server doesn’t need to generate and serve every page request. Instead, the client’s browser handles rendering subsequent content, leading to reduced server load and better scalability.

Disadvantages of Using Client-Side Rendering

While CSR offers many benefits, it’s important to consider its limitations –

SEO Challenges

Search Engine Optimization SEO

Search engines may have difficulty indexing content that’s loaded dynamically via JavaScript. Although search engines have improved handling JS-rendered content, CSR may still pose challenges for SEO.

Initial Load Performance

The initial load performance of a CSR-powered page heavily depends on JavaScript execution. Slow or heavy JavaScript can lead to delayed rendering and a poor user experience.

Limited Accessibility for Crawlers

Some web crawlers and social media bots may struggle to interpret dynamically loaded content, affecting how your content is shared and displayed on different platforms.

Adding Interactivity with React State and Hooks

We’ll harness the power of React state and hooks to make our Gatsby site more engaging. By utilizing the useState and useEffect hooks, we can create components that respond to user interactions in real time. For instance, we can develop an interactive blog post list that dynamically updates as users scroll, providing a seamless browsing experience.

import React, { useState, useEffect } from 'react';

const InteractiveBlogList = () => {
  const [posts, setPosts] = useState([]);

  useEffect(() => {
    // Fetch blog posts from an API and update state
    // This can be done using GraphQL queries or REST APIs
  }, []);

  return (
      { => (
        <div key={}>{post.title}</div>

export default InteractiveBlogList;

Creating Client-Only Routes

Gatsby uses @reach/router package to create client-side routes. The package is pre-installed, so we do not have to configure it in our project.

To create client-side pages, we need to create [...].js file in src/pages directory. This file is a router for our client-side routes. The file is a typical react component that imports required packages or components. The following is the minimal component that creates a three client-side routes –

// src/pages/[...].js

import React from 'react';
import { Router } from '@reach/router';

import Home from '../Components/Home';
import About from '../Components/About';
import Contact from '../Components/Contact';

const App = () => {
  return (
      <Home path="/" />
      <About path="/about" />
      <Contact path="/contact" />

export default App;

As you can see I’ve imported Router component from @reach/router package. We can use it to define our client-side routes. Components imported from the Component directory are normal react components that will be created in the users’ browser.

The path accepts the actual route. For example, / means the project root, /about is, etc.

Finally, export the component to finalize it.

The above is the bare minimum of a client-sided router. Just as we can send params and queries in CSR and SSR, we can also send data through URLs in CSR.

Sending params in CSR (Client-side Routes)

We can also send data (params or queries) in client-side routes. We can use the params to request specific data from the server in the user’s browser. Here is how to send params in client-side routes in Gatsby –

// src/pages/[...].js

import React from 'react';
import { Router } from '@reach/router';

import Home from '../Components/Home';
import Profile from '../Components/Profile';

const App = () => {
  return (
      <Home path="/" />
      <Profile path="/profile/:userId" />

export default App;

As you can see, in the Profile component, we can send params in the URL by defining it/them in the path. If the user visits /profile/123/123 will be available in the Profile component as a userId prop.

Implementing User Authentication

User authentication is a crucial aspect of many web applications. Gatsby makes it possible to integrate authentication providers like Auth0 or Firebase easily. By securing certain routes or components, we ensure that only authenticated users can access sensitive content.

import React from 'react';
import { navigate } from 'gatsby';
import { useAuth } from '../hooks/useAuth';

const PrivateRoute = ({ component: Component, location, }) => {
  const { isAuthenticated } = useAuth();

  if (!isAuthenticated && location.pathname !== '/login') {
    navigate('/login'); // Redirect unauthenticated users to the login page
    return null;

  return <Component {} />;

export default PrivateRoute;

We can build a separate component such as PrivateRoute and use it as a middleware to authenticate users’ requests. Authentication is a complicated topic and requires a separate article for discussion. However, the above component is an example of how we can check the user and redirect based on the current authentication state.


In this article, we’ve delved into the exciting realm of dynamic content and client-only routes in GatsbyJS. By using React state, client-only routes, and user authentication, developers can create interactive and feature-rich web applications.

With the knowledge gained from this article, you’re well-equipped to take your Gatsby projects to the next level of interactivity and user engagement. Stay tuned for more insights and tutorials in our ongoing GatsbyJS series!