How to use Grafbase as your backend with Next.js

Next.js is a popular choice when building applications at scale with React. Next.js provides several hooks to connect your backend — Grafbase.

The examples below will use this schema:

type Post @model {
  id: ID!
  title: String!
}

Next.js provides built-in functionality to generate pages at build time. This has many benefits including SEO, quicker loading times, reduced usage billing with your backend provider — Grafbase, and more.

If you export the function getStaticProps from a page, Next.js will run this at build time.

export async function getStaticProps() {
  const res = await fetch('YOUR_GRAFBASE_ENDPOINT', {
    method: 'POST',
    headers: {
      Accept: 'application/json',
      'Content-Type': 'application/json',
      'x-api-key': 'YOUR_GRAFBASE_API_KEY'
    },
    body: JSON.stringify({
      query: `
        query GetPosts {
          postCollection(first: 100) {
            edges {
              node {
                id
                title
              }
            }
          }
        }
      `
    })
  })

  const { postCollection } = await res.json()

  return {
    props: {
      postCollection
    }
  }
}

As well as fetching the static data on a single page, you can fetch it for multiple pages if you know the path for each page by using the function getStaticPaths.

With Grafbase you can fetch each post by ID, so we can use that to get the data we need for each specific page.

// pages/posts/[id].tsx

export async function getStaticPaths() {
  const res = await fetch('YOUR_GRAFBASE_ENDPOINT', {
    method: 'POST',
    headers: {
      Accept: 'application/json',
      'Content-Type': 'application/json',
      'x-api-key': 'YOUR_GRAFBASE_API_KEY'
    },
    body: JSON.stringify({
      query: `
        query GetPosts {
          postCollection(first: 100) {
            edges {
              node {
                id
              }
            }
          }
        }
      `
    })
  })

  const { postCollection } = await res.json()

  const paths = postCollection.map(({ id }) => ({
    params: { id }
  }))

  return { paths, fallback: 'blocking' }
}

export async function getStaticProps({ params }) {
  const { id } = params

  const res = await fetch('YOUR_GRAFBASE_ENDPOINT', {
    method: 'POST',
    headers: {
      Accept: 'application/json',
      'Content-Type': 'application/json',
      'x-api-key': 'YOUR_GRAFBASE_API_KEY'
    },
    body: JSON.stringify({
      query: `
        query GetPostById($id: ID!) {
          post(id: $id) {
            id
          }
        }
      `,
      variables: {
        id
      }
    })
  })

  const { post } = await res.json()

  return {
    props: {
      post
    }
  }
}

You could opt to build only your most visited posts, and leave everything else to generate on-demand using this method.

Next.js provides built-in functionality to automatically revalidate pages it previously built. This functionality works on a per-page basis, so you no longer need to wait while everything rebuilds.

In addiiton to the steps above using SSG you can also provide revalidate property value (in seconds).

export async function getStaticProps() {
  // ...

  return {
    props: {
      posts
    },
    revalidate: 10
  }
}

When a request is made to fetch the page and 10 seconds have passed since it was last generated, it will trigger another regeneration.

If you export the function getServerSideProps from a page, Next.js will run this on request.

export async function getServerSideProps(context) {
  const res = await fetch('YOUR_GRAFBASE_ENDPOINT', {
    method: 'POST',
    headers: {
      Accept: 'application/json',
      'Content-Type': 'application/json',
      'x-api-key': 'YOUR_GRAFBASE_API_KEY'
    },
    body: JSON.stringify({
      query: `
        query GetPosts {
          postCollection(first: 100) {
            edges {
              node {
                id
                title
              }
            }
          }
        }
      `
    })
  })

  const { postCollection } = await res.json()

  return {
    props: {
      postCollection
    }
  }
}

If you've worked with React outside a framework before then fetching client-side is probably already familiar.

In this example we'll fetch data directly from Grafbase without any GraphQL client using the useEffect hook provided by React.

You'll want to make sure users are authenticated using the issued token from your OIDC provider. Here we'll use Clerk as an example:

import { useEffect, useState } from 'react'
import { useAuth } from '@clerk/nextjs'

const Page = () => {
  const [data, setData] = useState(null)
  const [isLoading, setIsLoading] = useState(false)

  const { getToken } = useAuth()

  useEffect(() => {
    setLoading(true)

    fetch('YOUR_GRAFBASE_ENDPOINT', {
      method: 'POST',
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
        Authorization: `Bearer ${await getToken({
          template: 'YOUR_TEMPLATE_NAME'
        })}`
      },
      body: JSON.stringify({
        query: `
          query GetPosts {
            postCollection(first: 100) {
              edges {
                node {
                  id
                  title
                }
              }
            }
          }
        `
      })
        .then(res => res.json())
        .then(({ data: { postCollection } }) => {
          setData(postCollection)
          setLoading(false)
        })
    })
  })
}

Next.js provides API routes you can call directly from your frontend. Inside these you can do everything you can on the frontend to query, and mutate data in your backend.

Since API routes happen on the server you can safely use your API key without the need to authenticate users.

Here we'll fetch the same data as before, and return it as JSON:

export default function handler(req, res) {
  fetch('YOUR_GRAFBASE_ENDPOINT', {
    method: 'POST',
    headers: {
      Accept: 'application/json',
      'Content-Type': 'application/json',
      'x-api-key': 'YOUR_GRAFBASE_API_KEY'
    },
    body: JSON.stringify({
      query: `
        query GetPosts {
          postCollection(first: 100) {
            edges {
              node {
                id
                title
              }
            }
          }
        }
      `
    })
      .then(res => res.json())
      .then(({ data: { postCollection } }) => {
        res.status(200).json({ postCollection })
      })
  })
}

Since Grafbase is both frontend and backend agnostic, you can make send requests to Grafbase right inside your API routes.

Your Next.js project with Grafbase is waiting

Build and scale your Next.js application backed by your own GraphQL API.