IT

The Complete Guide to Next.js 15 Metatags — From og:image to hreflang

A practical guide to The Complete Guide to Next.js 15 Metatags — From og:image to hreflang, with a clear checklist, key risks to watch, and next steps for readers who want to compare options before acting.

The Complete Guide to Next.js 15 Metatags — From og:image to hreflang

Key Summary

  • Next.js 15 can declaratively manage static and dynamic meta tags through the Metadata API based on the App Router.
The Complete Guide to Next.js 15 Metatags — From og:image to hreflang
  • The generateMetadata() function allows automatic generation of per-page dynamic og:image, title, and description.
  • Twitter Card, hreflang, canonical URL, and structured data (JSON-LD) can all be controlled from a single file.
  • Incorrectly configured meta tags directly lead to social preview errors and drops in search rankings, so always check with the Meta Tag Checker before deploying.

Quick Answer: You can efficiently manage meta tags using the Metadata API in Next.js 15.

What Is the Next.js 15 Metadata API?

ItemValue
Next.js Version15
Metadata Management MethodMetadata API
Dynamic Metadata Generation FunctiongenerateMetadata()
Supported Meta Tag Typesog:image, title, description, Twitter Card, hreflang, canonical URL, JSON-LD
Meta Tag Checker LinkMeta Tag Checker

The App Router introduced in Next.js 13 provides a Metadata API that replaces the legacy component approach. In Next.js 15, this API has become even more refined, allowing you to control meta tags in two ways from layout.tsx and page.tsx files: by exporting a metadata object or by using the generateMetadata() function.

Static Metadata

The simplest form is to directly export a metadata object.

tsx
// app/page.tsx
import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: 'Next.js 15 Meta Tag Guide',
  description: 'Everything about Next.js meta tags, from og:image to hreflang',
}

This approach is suitable for static pages where content is finalized at build time — for example, a blog home page or an about page where the content doesn't change frequently.

Dynamic Metadata: generateMetadata()

For pages where content varies based on URL parameters — such as blog posts or product detail pages — use the generateMetadata() function.

tsx
// app/blog/[slug]/page.tsx
import type { Metadata, ResolvingMetadata } from 'next'

type Props = {
  params: { slug: string }
}

export async function generateMetadata(
  { params }: Props,
  parent: ResolvingMetadata
): Promise<Metadata> {
  const post = await fetchPost(params.slug)

  return {
    title: post.title,
    description: post.excerpt,
    openGraph: {
      title: post.title,
      description: post.excerpt,
      images: [{ url: post.ogImage, width: 1200, height: 630 }],
    },
  }

Since generateMetadata() runs on the server, it can perform database queries and external API calls. It returns a value of type Metadata, and Next.js automatically injects it into the tag.


How Do You Properly Configure og:image?

The Complete Guide to Next.js 15 Metatags — From og:image to hreflang visual 2

Open Graph images are the preview images that appear when a link is shared on social platforms like KakaoTalk, Slack, and Twitter. If configured incorrectly, blank images or broken layouts will be displayed, which significantly reduces click-through rates.

Basic og:image Configuration

tsx
export const metadata: Metadata = {
  openGraph: {
    title: 'Page Title',
    description: 'Page description',
    url: 'https://example.com/blog/my-post',
    siteName: 'Site Name',
    images: [
      {
        url: 'https://example.com/og/my-post.png',
        width: 1200,
        height: 630,
        alt: 'Post representative image',
      },
    ],
    locale: 'ko_KR',
    type: 'article',
  },
}

Dynamic og:image Generation in Next.js — ImageResponse

Next.js 15 supports server-side dynamic OG image rendering using ImageResponse from next/og. You can control the design entirely in code without any separate image editing.

tsx
// app/og/route.tsx
import { ImageResponse } from 'next/og'

export const runtime = 'edge'

export async function GET(request: Request) {
  const { searchParams } = new URL(request.url)
  const title = searchParams.get('title') ?? 'Default Title'

  return new ImageResponse(
    (
      <div
        style={{
          display: 'flex',
          fontSize: 60,
          background: '#0f172a',
          color: 'white',
          width: '100%',
          height: '100%',
          alignItems: 'center',
          justifyContent: 'center',
          padding: '40px',
        }}
      >
        {title}
      </div>
    ),
    { width: 1200, height: 630 }
  )
}

You can then reference this endpoint inside generateMetadata().

tsx
images: [{ url: `https://example.com/og?title=${encodeURIComponent(post.title)}` }]

Twitter Card Configuration

Twitter (now X) uses its own meta tag spec, but the Next.js Metadata API consolidates this under the twitter key.

tsx
export const metadata: Metadata = {
  twitter: {
    card: 'summary_large_image',
    title: 'Page Title',
    description: 'Page description',
    creator: '@handle',
    images: ['https://example.com/og/my-post.png'],
  },
}

The card value can be one of summary, summary_large_image, app, or player. For blog posts, summary_large_image is the most appropriate choice.


How to Complete Multilingual SEO with hreflang

The Complete Guide to Next.js 15 Metatags — From og:image to hreflang visual 3

hreflang tags signal to search engines which language and region each version of the same content is intended for. If you run both Korean and English versions of a site, this must be configured. Without it, Google may treat language-specific pages as duplicate content and penalize their search visibility.

Configuring hreflang with alternates

tsx
export const metadata: Metadata = {
  alternates: {
    canonical: 'https://example.com/ko/blog/my-post',
    languages: {
      'ko-KR': 'https://example.com/ko/blog/my-post',
      'en-US': 'https://example.com/en/blog/my-post',
      'ja-JP': 'https://example.com/ja/blog/my-post',
    },
}

Based on this configuration, Next.js automatically generates the following tags.

html
<link rel="canonical" href="https://example.com/ko/blog/my-post" />
<link rel="alternate" hreflang="ko-KR" href="https://example.com/ko/blog/my-post" />
<link rel="alternate" hreflang="en-US" href="https://example.com/en/blog/my-post" />
<link rel="alternate" hreflang="ja-JP" href="https://example.com/ja/blog/my-post" />

Why Canonical URL Configuration Matters

A canonical URL tag tells search engines "this URL is the original" when identical or similar content exists at multiple URLs. When duplicate URLs arise from pagination, UTM parameters, www vs. non-www differences, and similar cases, omitting a canonical tag causes search ranking signals to be split across URLs.

tsx
alternates: {
  canonical: 'https://example.com/blog/my-post',
}

Use absolute paths and maintain HTTPS and www consistency (with or without www) across the entire site.


Obtaining Rich Results with Structured Data (JSON-LD)

The Complete Guide to Next.js 15 Metatags — From og:image to hreflang visual 4

Structured data enables rich results in search, displaying additional information such as star ratings, authors, and publication dates. In Next.js, the recommended approach is to insert a `

🔧 Related Free Tools

Next useful step

Continue from this guide

Related