Next.js, a powerful React framework for building web applications, offers several features to improve SEO and optimise the user experience. One such feature is the Nextjs generateMetadata function, which is used to dynamically generate metadata for your web pages. Metadata includes elements such as the page title, description, and other meta tags that are critical for search engine optimisation (SEO) and social media sharing.
In this tutorial, we will explore how to use generateMetadata in Next.js, when to use it, and its benefits.
Table of Contents
What is NextjsgenerateMetadata
?
The generateMetadata
function in Next.js allows you to fetch and generate metadata dynamically for your pages. This function is particularly useful for pages that need to display unique metadata based on route parameters or fetched data.
The generateMetadata
function in Next.js is particularly useful for dynamically generating metadata for pages that depend on route parameters or fetched data, such as blog posts or product pages with unique IDs. This dynamic generation ensures that each page has specific and relevant metadata, which is beneficial for SEO (Search Engine Optimization).
Tutorial on generateMetadata
in Next.js
Next.js, a popular React framework, provides robust features for server-side rendering, static site generation, and client-side rendering. One of the notable features in Next.js is the generateMetadata
function, which allows you to define metadata for your pages. This tutorial will cover the usage, implementation, and advantages of generateMetadata
in the latest version of Next.js as of July 2024.
What is NextjsgenerateMetadata
?
generateMetadata
is a function in Next.js used to dynamically generate metadata for your pages. This includes information like the page title, description, open graph tags, and other HTML meta tags. Metadata is crucial for SEO (Search Engine Optimization), social media sharing, and enhancing the user experience.
Why use generateMetadata
?
- SEO Benefits: Properly defined metadata improves the visibility of your website in search engine results.
- Dynamic Content: Generate metadata based on dynamic content, making your site more relevant to users.
- Social Media Optimization: Ensures that your pages are properly represented when shared on social media platforms.
- Improved User Experience: Providing accurate titles and descriptions helps users understand the content of your pages.
When to use generateMetadata
?
- Dynamic Pages: Use
generateMetadata
for pages that display dynamic content such as blog posts, products, or user profiles. - SEO Optimization: When you want to improve SEO by providing unique metadata for each page.
- Social Sharing: To enhance the appearance of your pages when shared on social media platforms.
Static vs. Dynamic Metadata in Next.js
Metadata in Next.js helps search engines and social media platforms understand your content. It can be either static or dynamic, each serving different purposes:
Static Metadata
- Fixed Information: Static metadata remains the same across the entire page or content.
- One-time Definition: Defined once and does not change based on conditions or parameters.
- Common Use: Often used for general page information like site-wide SEO settings or default metadata for pages that don’t change often.
Using Head
Component Directly in Page Components
Example of page with Static metadata, Defined in a static site or page that doesn’t require frequent updates. To provide specific metadata for each page, we should place the Head
component directly within each page component like below, even we have shared layout component with header.
export default function AboutPage() {
return (
<Head>
<title>About Us</title>
<meta name="description" content="Learn more about our company." />
</Head>
{/* Page content */}
);
}
Understanding the Problem
In Next.js, it’s common to share components like headers and footers across multiple pages. The challenge lies in managing metadata within these shared components of the Layout.tsx
Solution: Using Head
Component in Layout
Next.js provides a Layout
component structure to encapsulate shared elements. We can place the Head
component within the layout to manage metadata for all pages that use that layout. If some of your page need some different metadata then you can take our first static solution by importing Head directly to that page.
Or we have better option below, by using combining both static and dynamic.
// pages/about.js
import Layout from '../components/Layout';
import Head from 'next/head';
export default function AboutPage() {
return (
<Layout>
<Head>
<title>About Us</title>
<meta name="description" content="Learn more about our company." />
</Head>
{/* Page content */}
</Layout>
);
}
Dynamic Metadata
- Variable Information: Dynamic metadata can change based on specific conditions, parameters, or fetched data.
- Contextual Adjustments: Allows metadata to be customized for different scenes, products, or blog posts.
- Enhanced SEO: Provides more relevant and precise metadata for each page, improving search engine indexing and social media shareability.
Dynamic Metadata Example for all blogpost or all products using its id
Let generate blog post dynamic Metadata for each blog post using ID, or we can used in a products page/[slug] where metadata changes based on the product ID:
Here’s a step-by-step guide to implementing generateMetadata
in your Next.js application. In this case we are putting generateMetadata directly on the page it self instead of layout that can shared with all page within that folder.
Step 1: Create a Next.js Project
If you haven’t already, create a new Next.js project using the following command:
codenpx create-next-app@latest my-nextjs-app
cd my-nextjs-app
Step 2: Setup a Page Component
Let’s assume we have a page at app/blogs/[slug]
/page.tsx or app/products/[slug]
/page.tsx that displays individual blog posts or product detail. We want to generate metadata for each blog post based on its content.
export async function generateMetadata({ params }) {
const { id } = params;
const blog = await fetch(`https://api.example.com/blogs/${id}`).then(res => res.json());
return {
title: blog.name,
description: blog.description,
openGraph: {
title: blog.name,
description: blog.description,
images: [{ url: blog.image }],
},
alternates: {
canonical: `${getCanonicalUrl()}/products/${params.slug}`,
},
OR
alternates: {
canonical: `https://somedomain.com/products/${params.slug}`,
},
};
}
export default function BlogPage({ Blog }) {
// Page component code here
}
Or with supabase, we can have full code as below here
Instead of adding the base URL directly in the generateMetadata or by calling getCanonicalUrl()
from the utils/index.ts
file, we can use metadataBase
. This is a convenience option to set a base URL prefix for metadata fields that require a fully qualified URL.
export const getCanonicalUrl = () => {
return process.env.NODE_ENV !== "production"
? "http://localhost:3000"
: "https://nextjs-crash-course-theta.vercel.app";
};
export const getImageUrl = (imageUrl: string) => {
return `${process.env.NEXT_PUBLIC_SUPABASE_URL}/storage/v1/object/public/storage/${imageUrl}`;
};
No in canonical we don’t need to add baseURL on canonical property, as shown by selecting color red on the where we edit the code.
import { createClient } from "@/supabase/client";
import { getCanonicalUrl, getImageUrl } from "@/utils";
import { Metadata, ResolvingMetadata } from "next";
import Image from "next/image";
import { notFound } from "next/navigation";
export const revalidate = 0;
type Props = {
params: { slug: string };
searchParams: { [key: string]: string | string[] | undefined };
};
// For dynamic meta data for SEO
export async function generateMetadata(
{ params }: Props,
parent: ResolvingMetadata
): Promise<Metadata> {
const slug = params.slug;
const supabase = createClient();
const { data: post } = await supabase
.from("blog-posts")
.select()
.eq("id", slug)
.single();
if (!post) {
return { title: "", description: "" };
}
return {
metadataBase: new URL(getCanonicalUrl()),
title: post.title || "", // Optional chaining for safety
description: post.content.slice(0, 160) || "", // Summary for description
openGraph: {
images: [getImageUrl(post.imageUrl)],
},
alternates: {
canonical: `/blog/${params.slug}`,
},
};
}
export async function generateStaticParams() {
const supabase = createClient();
const { data: posts } = await supabase.from("blog-posts").select("id");
if (!posts) { return [];}
return posts.map((post) => ({
params: { slug: post.id },
}));
}
export default async function Page({ params }: Props) {
const supabase = createClient();
const { data } = await supabase.from("blog-posts").select().eq("id", params.slug).single();
if (!data) {
notFound();
}
return (
<div className="px-12 py-12 max-w-7xl mx-auto min-h-screen">
....
</div>
);
}
Dynamic Metadata using generateMetadata
on shared layout file
To generate dynamic metadata for all the new upload blog or product, let create folder upload inside the blogs inside we have folder /[slug] and upload . We have already discuss about the generating dynamic metadata on single page in previous section. Now lets create dynamic metadata in blogs/upload having two files layout.tsx and page.tsx. We only need to used layout.tsx file to add dynamic metadata.
import { getCanonicalUrl } from "@/utils";
import { Metadata } from "next";
export const metadata: Metadata = {
metadataBase: new URL(getCanonicalUrl()),
title: "Easy Sell - Upload",
description: "Upload your files easily using Easy Sell",
alternates: {
canonical: "/",
},
openGraph: {
images: ["/assets/og-image.png"],
},
};
export default function Layout({ children }: { children: React.ReactNode }) {
return (
// Do what you need to do
<>{children}</>
);
}
In conclusion, generateMetadata in Next.js is a powerful tool for dynamically creating metadata, optimizing SEO, and improving social sharing. By using it correctly, you can ensure that your web application provides a better user experience and ranks higher in search engine results. Check offical Next.js documentation on generateMetadata.
Related blog post on nextjs
- Mastering generateStaticParams() in Next.js 14: Boost Performance and SEO
- Understanding Nextjs Server Actions and Mutations 2024
- Understanding Routing in Next.js
- Understanding Prefetching in Next.js
- Data Fetching and Caching in Next.js