WDD 430: Web Full-Stack Development

Adding Metadata

Overview

Metadata provides information about a webpage that is not displayed on the page itself but is used by browsers, search engines, and other web services. Adding metadata to your Next.js application helps improve SEO, accessibility, social media sharing, and overall discoverability.

Prepare

What is Metadata?

Metadata includes elements like the page title, description, keywords, and Open Graph tags. These elements help search engines understand the content of your page and how to display it in search results and when shared on social media platforms.

Why is metadata important?

Metadata is crucial in improving the visibility and performance of your website in search engine results and social media platforms. Metadata helps search engines effectively index and display your content. Metadata like Open Graph tags can significantly enhance how your pages appear when shared on social media.

Types of Metadata

There are several types of metadata that serve different purposes:

We start with the raw HTML tags so you can understand what each metadata field does. Then, in Next.js, you will map these concepts to the metadata export and generateMetadata() so they can be managed per route.

Title Metadata

Responsible for the title of a webpage that is displayed on the browser tab. It's crucial for SEO as it helps search engines understand what the webpage is about.

<title>Page Title</title>
Description Metadata

Provides a brief summary or overview of the webpage's content. It's used by search engines to display a snippet of text in search results which lets users know what the page is about in order to make a decision about whether to click through.

<meta name="description" content="Brief description of the page content." />
Open Graph Metadata

Open Graph tags allow you to control how your webpage appears when shared on social media platforms like Facebook and LinkedIn. These tags provide information about the title, description, a preview image, and other details that will be displayed.

X (formerly known as Twitter) also supports its own twitter: tags (for example, twitter:card and twitter:title). If those are missing, X will often fall back to Open Graph tags, so well-written OG metadata is still an important baseline.

<meta property="og:title" content="Page Title" />
<meta property="og:description" content="Brief description of the page content." />
<meta property="og:image" content="path/to/image.jpg" />
Favicon Metadata

Controls the icon that appears in the browser tab for your webpage. It's a small image that represents your website.

<link rel="icon" href="/favicon.ico" />

In App Router projects, Next.js supports convention-based icons. If you place files like favicon.ico, icon.png, or apple-icon.png in the app/ directory, Next.js can wire them up automatically, so you usually do not need to write a manual <link rel="icon" ...> tag.

How to Add Metadata in Next.js

Next.js includes a built-in Metadata API that automatically generates the correct code for the <head> elements for your pages instead of manually adding metadata. There are two ways to add metadata in Next.js and with both options, Next.js will automatically generate the relevant <head> elements for your pages.

Config-based metadata (static and function-based) is defined directly in your layout.tsx or page.tsx files. You can export a static metadata object for content that does not change, or use a generateMetadata function for dynamic metadata that depends on route params or fetched data.

File-based metadata relies on Next.js recognizing specially named files placed in your project. For example, add favicon.ico, icon.png, or apple-icon.png to your app/ folder and Next.js wires them up automatically. The same approach applies to social preview images such as opengraph-image.png, along with files like robots.txt and sitemap.xml. These files can be static assets or generated programmatically.

Activity Instructions

Favicon and Open Graph image

  1. Add a favicon.ico file to your app/ folder. If you want an Apple touch icon too, add apple-icon.png.
  2. Add an opengraph-image.png file to your app/ folder so shared links have a preview image.
  3. Start your development server and confirm that the favicon appears in the browser tab.
  4. Inspect the generated page source or use a sharing debugger to confirm that the Open Graph image is included in the page metadata.

Page titles and descriptions

You can define a metadata object in any layout.tsx or page.tsx file to set titles and descriptions for that route segment.

  1. Define site-wide defaults in your app/layout.tsx file.
import type { Metadata } from 'next';

export const metadata: Metadata = {
  title: {
    default: 'Student Name | Project Portfolio',
    template: '%s | Project Portfolio',
  },
  description:
    'A portfolio of web development projects.',
  metadataBase: new URL('https://your-portfolio-url.vercel.app'),
};

Next.js uses this configuration to generate the <title> element and related meta tags. The default title is used when a page does not define its own title, and the template lets you keep a consistent format across the site.

  1. Add page-specific metadata when a route needs its own title.
import type { Metadata } from 'next';

export const metadata: Metadata = {
  title: 'Open Source',
};
  1. For dynamic routes such as individual project pages, use generateMetadata() to build the metadata from route params or fetched data.
import type { Metadata } from 'next';
import { notFound } from 'next/navigation';
import { fetchProjectById } from '@/app/lib/data';

type Props = {
  params: Promise<{ id: string }>;
};

export async function generateMetadata({ params }: Props): Promise<Metadata> {
  const { id } = await params;
  const project = await fetchProjectById(id);

  if (!project) {
    return {
      title: 'Project Not Found',
      description: 'The requested portfolio project could not be found.',
    };
  }

  return {
    title: project.title,
    description: project.summary,
    openGraph: {
      title: project.title,
      description: project.summary,
      images: project.imageUrl ? [project.imageUrl] : [],
    },
  };
}

export default async function Page({ params }: Props) {
  const { id } = await params;
  const project = await fetchProjectById(id);

  if (!project) notFound();

  return <h1>{project.title}</h1>;
}

With this setup, your portfolio can provide accurate metadata for both static pages and dynamic project routes, improving search visibility and social sharing previews.