Skip to content

Next's Metadata API

Video Summary

All of the projects we've seen so far are missing one pretty important thing: a title!

Screenshot of the previous exercise, showing a Chrome window with a nameless tab

This happens because we haven't included a <title> in the <head> of our document.

One way to fix this is to include it in our layout.js. After all, React owns the entire DOM when we work with Next!

function FlashMsgLayout({ children }) {
return (
<html lang="en">
<head>
<title>Inline title</title>
</head>
<body>
<ToastProvider>
{children}
<ToastShelf />
</ToastProvider>
</body>
</html>
);
}

This is a perfectly viable solution, but there's a more conventional way to do this in Next: the Metadata API.

Here's how it works: from any layout.js or page.js component, we can export a JS object that contains information about the page's metadata:

export const metadata = {
title: 'Metadata Title',
};
function FlashMsgLayout({ children }) {
return (
<html lang="en">
<body>
<ToastProvider>
{children}
<ToastShelf />
</ToastProvider>
</body>
</html>
);
}

The metadata object can include lots of stuff: the page title, descriptions and other metadata for search engines, OpenGraph images, favicons… That said, I mostly use it for filling in text-based tags; as part of the Metadata API, things like favicons and OG images will automatically be included if we add those images to the /app directory.

When Next renders this page, it'll notice that we've exported a metadata object, and use it to automatically create and inject a <title> into the <head> of the document.

We can export metadata objects from multiple files: metadata in a page.js will be merged with the metadata in layout.js, allowing us to set a default value in the layout, and to overwrite it as-necessary in particular pages.

This will work in most cases, but every now and then, you'll hit a situation which requires a bit more control.

Earlier, we built the world's most boring social network. I think it'd be nice if the <title> was specific to the current profile. That's the way it works on Twitter!

For example, when we're visiting María's profile, we should see her name in the title:

Screenshot of the social network, showing Maria's profile, with the title “María José Ramirez’s profile”

This is tricky, because the exact value will depend on the dynamic segment. We don't have access to that outside the Page component!

Fortunately, Next has an escape hatch for this exact situation. Instead of exporting a static metadata object, we can export a dynamic generateMetadata function.

Here's what it looks like:

export async function generateMetadata({ params }) {
const profile = await getProfileInfo(params.profileId);
return {
title: `${profile.name}’s profile`,
};
}

When Next renders this page, it notices we've exported this function. It then invokes this function with the same arguments it passed to our component!

We return a Metadata object, the same type of object we had been exporting before. Except now, it'll be dynamically recalculated based on the route params!

In cases like this, the generateMetadata function is an absolute lifesaver. 💯

You can learn much more about the Metadata API in the Next docs (opens in new tab).