Dynamic Metadata Generation and Data Fetching at Once in Next.js App Router

Nitish Kumar Singh

Feb 17, 2024 . 4 min read

Hello developers! In this blog post, we will explore how we can dynamically generate metadata and also fetch server component data by making a single fetch request in the page.js file in the Next.js App Router.

Metadata generation in Next.js

We all know that Next.js provides the generateMetadata function for dynamic metadata generation. We can generate metadata by exporting the generateMetadata function as shown in the code below:

export async function generateMetadata() {
  let metaData = await getMetadata();
  return metaData;
}

Where the getMetadata function fetches data from the database, creates an object of Metadata with properties as desired, and returns it. You can explore and find the required list of properties (fields) of the Metadata object from the Next.js Docs. For example, the code below returns a metadata object with minimal fields:

const getMetadata = async ()=>{
    const res = await fetch("URL to fetch your metadata from database");
    if (res.ok) {
        const data = await res.json();
        return {
            title:data.title,
            description:data.desc,
            alternates: {
              canonical: 'https://code.nkslearning.com'+data.path
            },
            openGraph: {
              title: data.title,
              description: data.desc,
              url: 'https://code.nkslearning.com'+data.path,
              siteName: 'NKS CODING LEARNINGS',
              images: [{url: data.img}],
              type: 'article',
              publishedTime:data.publishedTime,
              authors:["NITISH KUMAR SINGH"]
            }
        };
    }else{
        // return default metadata or {} if default metadata exported from layout file
        return {};
    }
}

But what if we want to make only a single fetch request to fetch all data at once, meaning data that we fetch in both the server component and generateMetadata function? In my case, I have stored all blog post data in a single document in the Appwrite database. So why make two requests to get data from the same place when I can get it all at once and also improve performance?

To achieve this, let's first understand what actually happens when we visit /a-route in a Next.js app. Next.js first calls the server component function of that route, then just after a few milliseconds, it calls the generateMetadata function, whether the server component has finished its work or not, and waits until generateMetadata returns the metadata object.

So I have tried some techniques to achieve what I want, and below is the code to bring metadata from the data fetched in the server component:

export async function generateMetadata() {
  let metaData = await getMetadata();
  return metaData;
}
var resolve;
const getMetadata = ()=>{
    return new Promise((res)=>{
        if (resolve && typeof resolve === "object") {
            res(resolve);
        }else resolve = res;
    });
}

As mentioned above, Next.js first calls the server component function, then the generateMetadata function. Therefore, in the getMetadata function, I have checked whether the metadata object is already initialized in the resolve variable (which almost never happens, but I added it for safety). If yes, then simply return it via the resolve function of Promise. If not, then initialize the resolve variable with the resolve (res)  function of Promise.

Now let's handle the rest of the work in the server component, and below is the code to fetch data from the database and send it to the generateMetadata function:

export default async function BlogPost({params}) {
    let blogInfo = await fetchData(params);
    const me = {
        title:blogInfo.title,
        description:blogInfo.desc,
        alternates: {
        canonical: blogInfo.path
        },
        openGraph: {
        title: blogInfo.title,
        description: blogInfo.desc,
        url: 'https://code.nkslearning.com'+blogInfo.path,
        siteName: 'NKS CODING LEARNINGS',
        images: [{url: blogInfo.img}],
        type: 'article',
        publishedTime:blogInfo.$updatedAt,
        authors:["NITISH KUMAR SINGH"]
        }
    };
    if (resolve && typeof resolve === "function") resolve(me); else resolve = me;
    return (<BlogPostPage blogInfo={blogInfo}/>);
}

Here, the fetchData function fetches data from the database and returns it in JS object form. Then it creates a Metadata object, sends it to the generateMetadata function, or stores it in the resolve variable and sends this fetched data to the child component.

This is the process to fetch the required data in a single request and handle dynamic metadata generation. I hope you understand it and find this post helpful. Happy Coding!

Published on Feb 17, 2024
Comments (undefined)

Read More

How to Save Content of a Web Page Element as PDF using JavaScript

Hello developers! In this blog post, I will show you a solution to a question that I have recently faced: how can we save or create a PDF file from the content of a web page element using JavaScript?

Feb 16, 2024

How to Create a Color Picker Web App using JavaScript - Part 3

Hello developers! In this blog post, we will continue the color-picker web app project and understand how to write the rest of JavaScript logic code for our color-picker.

Feb 14, 2024

How to Create a Color Picker Web App using JavaScript - Part 1

Hello developers! In this blog post, we will create a Color Picker Web App using JavaScript and understand how to design a color picker UI.

Jan 29, 2024

How to Create a Color Picker Web App using JavaScript - Part 2

Hello developers! In this blog post, we will continue the color-picker web app project and understand how to write JavaScript logic code for our color-picker.

Feb 12, 2024

Writing a Regex to Validate an Input String for Setting It as Padding on an Element in JS

Hello developers! In this blog post, we will going to write a Regular Expression to validate an input string to set this string as padding of an Element in JavaScript.

Feb 11, 2024

What are Regex or Regular Expressions in JavaScript and their Usages

Hello developers! In this blog post, we will explore Regular Expressions (Regex) in JavaScript, exploring their functionalities and applications. We'll learn how to define Regex patterns while adhering to their rules and uncover various ways to utilize them effectively.

Feb 6, 2024