When working on a Next.js-based website, you might encounter the need to fetch data from an API at build time. In this article, I’ll share a solution that works both in development (localhost) and in production (Vercel) environments.

Let’s consider a scenario where we have a list of “members” and we want to download this data once, store it, and make it available across all pages. The list of members is relatively static and changes at most once a day. If any changes occur, we can programmatically trigger a redeploy using Vercel’s Deploy Hooks.

Here’s the plan:

  1. Create a local cache file named .members to store the data.
  2. Implement a function in the lib/members.js file to fetch and store the data in the cache as JSON.
  3. Read the data from the cache when needed.

First, let’s create the lib/members.js file with the following code:

import fs from 'fs'
import path from 'path'

// Function to fetch members data from the API
function fetchMembersData() {
  console.log('Fetching members data...')
  return [
    { email: '[email protected]' },
    { email: '[email protected]' }
  ]
}

// Path to the cache file
const MEMBERS_CACHE_PATH = path.resolve('.members')

// Function to get the members data
export default async function getMembers() {
  let cachedData

  // Try reading the cache file
  try {
    cachedData = JSON.parse(
      fs.readFileSync(path.join(__dirname, MEMBERS_CACHE_PATH), 'utf8')
    )
  } catch (error) {
    console.log('Member cache not initialized')
  }

  // If cache is empty, fetch the data and write to the cache file
  if (!cachedData) {
    const data = fetchMembersData()

    try {
      fs.writeFileSync(
        path.join(__dirname, MEMBERS_CACHE_PATH),
        JSON.stringify(data),
        'utf8'
      )
      console.log('Wrote to members cache')
    } catch (error) {
      console.log('ERROR WRITING MEMBERS CACHE TO FILE')
      console.log(error)
    }

    cachedData = data
  }

  return cachedData
}

To use the getMembers() function in any page, import it with the following code:

import getMembers from 'lib/members'

Inside the getStaticProps() function, fetch the members data using await getMembers():

const members = await getMembers()

Now, you can use the members data in various ways within your page components. For example, you can add it to the props object returned by getStaticProps and iterate over it in the page component like this:

{members?.map((member) => {
  return (
    <p key={member.email} className='mt-3'>
      {member.email}
    </p>
  )
})}

That’s it! With this approach, you can cache data globally across all pages in Next.js at build time, ensuring efficient data retrieval and usage.