Managing Metadata in Next.js 14 for Enhanced SEO and User Experience
Tags: nextjs, webdev, beginners, tutorial
Published: 2024-07-02 11:13:43

## Introduction

In Next.js 14, there are two primary ways to manage metadata for your application: using a static `metadata` object or a dynamic `generateMetadata` function. Below is a detailed guide on how to utilize both options effectively.

This guide provides an in-depth look at both approaches, helping you understand how to effectively implement metadata in your Next.js application.

## Next.js Demo with Metadata Output

In this live example, we'll create a simple Next.js application showcasing the usage of metadata.  Then, we'll view the rendered output in the browser and visualise the metadata in action.

We start by creating a new Next.js project with `create-next-app`

```bash
npx create-next-app@latest
```

Here's the options I chose while creating it.

![create-next-app-choices](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y5hn3c2c4gbo49ujcmen.png)

Add this sample code in the following block and let's preview it in the browser.

**Code:**

![nextjs-metadata-code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4dplnm94rwbwm2e0jl7q.png)

**Output:**

And here's the browser output with get with the tags, keep reading the entire article to see how you could implement in your code.

![nextjs-metadata-output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qdx7yd4pwc0tlenu4rgi.png)

### Static Metadata

To define static metadata, you export a `Metadata` object from a `layout.ts` or `page.ts` file using the App Router.

Example:

```typescript
import { Metadata } from 'next'

export const metadata: Metadata = {
  title: 'Static Page Title',
  description: 'This is a static page description',
}

export default function Page() {}
```

This method is suitable when the metadata does not depend on runtime information.

### Dynamic Metadata

Dynamic metadata allows you to generate metadata based on dynamic data, such as route parameters or fetched data.

Example:

```typescript
import { Metadata, ResolvingMetadata } from 'next'

type Props = {
  params: { id: string }
  searchParams: { [key: string]: string | string[] | undefined }
}

export async function generateMetadata(
  { params, searchParams }: Props,
  parent: ResolvingMetadata
): Promise<Metadata> {
  const id = params.id
  const product = await fetch(`https://api.example.com/products/${id}`).then((res) => res.json())

  const previousImages = (await parent).openGraph?.images || []

  return {
    title: product.name,
    description: product.description,
    openGraph: {
      images: [product.imageUrl, ...previousImages],
    },
  }
}

export default function Page({ params, searchParams }: Props) {}
```

This method is useful when the metadata depends on dynamic data or needs to extend parent metadata.

### Key Points

- **Server Components Only**: Both `metadata` and `generateMetadata` are only supported in Server Components.
- **Single Export Rule**: You cannot export both the `metadata` object and `generateMetadata` function from the same route segment.

### Metadata Fields

Next.js provides a variety of metadata fields to customize the metadata of your application comprehensively.

#### Title

- **String**
  ```typescript
  export const metadata: Metadata = {
    title: 'Next.js Application',
  }
  ```
  Output: `<title>Next.js Application</title>`

- **Template Object**
  ```typescript
  export const metadata: Metadata = {
    title: {
      template: '%s | Next.js',
      default: 'Next.js',
    },
  }
  ```
  Output in child routes: `<title>About | Next.js</title>`

- **Absolute**
  ```typescript
  export const metadata: Metadata = {
    title: {
      absolute: 'About Us',
    },
  }
  ```
  Output: `<title>About Us</title>`

#### Description

```typescript
export const metadata: Metadata = {
  description: 'The React Framework for the Web',
}
```

Output: `<meta name="description" content="The React Framework for the Web" />`

#### Basic Fields

```typescript
export const metadata: Metadata = {
  generator: 'Next.js',
  applicationName: 'Next.js App',
  keywords: ['Next.js', 'React', 'JavaScript'],
  authors: [{ name: 'Author Name', url: 'https://example.com' }],
}
```

Output:

```html
<meta name="generator" content="Next.js" />
<meta name="application-name" content="Next.js App" />
<meta name="keywords" content="Next.js,React,JavaScript" />
<meta name="author" content="Author Name" />
<link rel="author" href="https://example.com" />
```

#### Open Graph

```typescript
export const metadata: Metadata = {
  openGraph: {
    title: 'Next.js',
    description: 'The React Framework for the Web',
    url: 'https://nextjs.org',
    siteName: 'Next.js',
    images: [
      {
        url: 'https://nextjs.org/og.png',
        width: 800,
        height: 600,
      },
    ],
    locale: 'en_US',
    type: 'website',
  },
}
```

Output:

```html
<meta property="og:title" content="Next.js" />
<meta property="og:description" content="The React Framework for the Web" />
<meta property="og:url" content="https://nextjs.org/" />
<meta property="og:site_name" content="Next.js" />
<meta property="og:locale" content="en_US" />
<meta property="og:image" content="https://nextjs.org/og.png" />
<meta property="og:image:width" content="800" />
<meta property="og:image:height" content="600" />
```

#### Twitter

```typescript
export const metadata: Metadata = {
  twitter: {
    card: 'summary_large_image',
    title: 'Next.js',
    description: 'The React Framework for the Web',
    images: ['https://nextjs.org/og.png'],
  },
}
```

Output:

```html
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="Next.js" />
<meta name="twitter:description" content="The React Framework for the Web" />
<meta name="twitter:image" content="https://nextjs.org/og.png" />
```

#### Robots

```typescript
export const metadata: Metadata = {
  robots: {
    index: false,
    follow: true,
    googleBot: {
      index: true,
      follow: false,
    },
  },
}
```

Output:

```html
<meta name="robots" content="noindex, follow" />
<meta name="googlebot" content="index, nofollow" />
```

#### MetadataBase

`metadataBase` allows setting a base URL prefix for metadata fields that require a fully qualified URL.

Example:

```typescript
export const metadata: Metadata = {
  metadataBase: new URL('https://example.com'),
  openGraph: {
    images: '/og-image.png',
  },
}
```

Output:

```html
<meta property="og:image" content="https://example.com/og-image.png" />
```

### Best Practices

- **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.

- **Combine Metadata Fields**: Utilize a combination of different metadata fields to ensure comprehensive metadata coverage for SEO and social media integration.

- **Utilize `metadataBase`**: Set a `metadataBase` in your root layout to simplify URL-based metadata field definitions.

## Conclusion

By following these guidelines, you can effectively manage metadata in your Next.js 14 application, enhancing both SEO and user experience.

Thank you for reading! If you found this blog post helpful, please consider sharing it with others who might benefit. Feel free to check out my other blog posts and visit my socials!

- [Profile](https://bio.link/devarshishimpi)
- [Linkedin](https://linkedin.com/in/devarshi-shimpi)
- [Twitter](https://twitter.com/devarshishimpi)
- [Youtube](https://youtube.com/@devarshishimpi)
- [Hashnode](https://devarshishimpi.hashnode.dev)
- [DEV](https://dev.to/devarshishimpi)

### Read more

- [What Are Docker Images And How To Use Them](https://blog.devarshi.dev/what-are-docker-images-and-how-to-use-them)
- [Creating Your First Droplet - DigitalOcean Tutorials](https://blog.devarshi.dev/creating-your-first-droplet-digitalocean-tutorials)
- [Setting Up An Ubuntu EC2 Instance From Scratch on AWS](https://blog.devarshi.dev/setting-up-an-ubuntu-ec2-instance-from-scratch-on-aws)