Here, I am using App Router.
Static Metadata
// layout.js
export const metadata = {
title: "Static Page Title",
description: "This is a static page description"
}
export default function Page() {}
Dynamic MetaData using generateMetadata
Dynamic metadata allows you to generate metadata based on dynamic data, such as route parameters or fetched data.
Example:
// [dynamic-route]/page.jsx
export async function generateMetadata({ params }) {
return {
title: product.title,
description: product.description,
openGraph: {
title: product.title,
description: product.description,
url: product.url,
images: [
{
url: product.imageUrl,
width: 800,
height: 600,
alt: product.title,
}
],
type: 'website'
},
twitter: {
card: 'summary_large_image',
title: product.title,
description: product.description,
images: [product.imageUrl]
}
};
}
}
}
export default function Page({ params, searchParams }) {}
note: post
is an object containing the information of a blog post.
NOTES:
- Use Static Metadata When Possible: If metadata doesn’t depend on runtime information, prefer static metadata for simplicity.
- Dynamic Metadata for Dynamic Data: Use
generateMetadata
for routes where metadata depends on dynamic data or needs to extend parent metadata.
DYNAMIC METADATA using next/head
For example, if you are building a blog and want each post to have its own title — you can do this with dynamic Metadata.
import Head from 'next/head'
export default function BlogPost({ post }) { // post is an object that contains information about the blog post.
return (
<>
<Head>
<title>{post.title} | My Blog</title>
<meta name="description" content={post.description} />
<meta property="og:title" content={post.title} />
<meta property="og:description" content={post.description} />
<meta property="og:image" content={post.image} />
<meta property="og:type" content="article" />
<meta property="og:url" content={`https://my-site.com/blog/${post.slug}`} />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={post.title} />
<meta name="twitter:description" content={post.description} />
<meta name="twitter:image" content={post.image} />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta charset="UTF-8" />
</Head>
<h1>{post.title}</h1>
<p>{post.content}</p>
</>
)
}
Import the Head component
Next.js provides a Head
component that you can use to add elements to the <head>
of your HTML document.
import Head from 'next/head'
Use the Head component
You can use the Head
component in your component as follows:
<Head>
......................
....ALl codes here....
......................
</Head>
For Meta Title and Meta Description
import Head from 'next/head'
export default function BlogPost({ post }) { // post is an object that contains information about the blog post.
return (
<>
<Head>
<title>{post.title} | My Blog</title>
<meta name="description" content={post.description} />
</Head>
<h1>{post.title}</h1>
<p>{post.content}</p>
</>
)
}
For OpenGraph Title, Description & Image
import Head from 'next/head'
export default function BlogPost({ post }) { // post is an object that contains information about the blog post.
return (
<>
<Head>
<title>{post.title} | My Blog</title>
<meta name="description" content={post.description} />
<meta property="og:description" content={post.description} />
<meta property="og:image" content={post.image} />
<meta property="og:type" content="article" />
<meta property="og:url" content={`https://my-site.com/blog/${post.slug}`} />
</Head>
<h1>{post.title}</h1>
<p>{post.content}</p>
</>
)
}
For Twitter Title, Description & Image
import Head from 'next/head'
export default function BlogPost({ post }) { // post is an object that contains information about the blog post.
return (
<>
<Head>
<title>{post.title} | My Blog</title>
<meta name="description" content={post.description} />
<meta property="og:description" content={post.description} />
<meta property="og:image" content={post.image} />
<meta property="og:type" content="article" />
<meta property="og:url" content={`https://my-site.com/blog/${post.slug}`} />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={post.title} />
<meta name="twitter:description" content={post.description} />
<meta name="twitter:image" content={post.image} />
</Head>
<h1>{post.title}</h1>
<p>{post.content}</p>
</>
)
}
Last 2 Fields (Meta Viewport & Meta charset) (Note: These are Default Fields by NextJS)
There are two default meta
tags given by NEXTJS — that are always added even if a route doesn’t define metadata:
- The meta charset tag sets the character encoding for the website.
- The meta viewport tag sets the viewport width and scale for the website to adjust for different devices.
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
Good to know: You can overwrite the default
viewport
meta tag.
Additional Optimisations:
Previews and Rich Snippets
Consider using structured data (JSON-LD) to improve rich snippets in search results.
<script type="application/ld+json">
{`
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "${post.title}",
"image": "${post.image}",
"author": "${post.author}",
"publisher": {
"@type": "Organization",
"name": "My Blog",
"logo": {
"@type": "ImageObject",
"url": "https://my-site.com/logo.png"
}
},
"datePublished": "${post.datePublished}"
}
`}
</script>
Check the sources:
- https://dev.to/adrianbailador/metadata-and-dynamic-metadata-in-nextjs-3e9m