項目 | 説明 |
Config-based Metadata | layout.js やpage.js ファイル内で、static metadata objectまたは動的な[generateMetadata function](https://beta.nextjs.org/docs/api-reference/metadata#generatemetadata)をエクスポートして、metadataを定義する方法。 |
File-based Metadata | route segmentに特別なファイルを静的または動的に追加することでmetadataを定義する方法。 |
[metadata object](https://beta.nextjs.org/docs/api-reference/metadata#metadata-object) | 静的metadataを定義するには、layout.js または静的page.js ファイルから[Metadata object](https://beta.nextjs.org/docs/api-reference/metadata#metadata-fields)をエクスポートします。 |
[generateMetadata function](https://beta.nextjs.org/docs/api-reference/metadata#generatemetadata-function) | 動的metadataは、現在のルートパラメータ、外部データ、または親セグメントのmetadata などの動的情報に依存する場合、[Metadata object](https://beta.nextjs.org/docs/api-reference/metadata#metadata-fields)を返すgenerateMetadata 関数をエクスポートすることで設定できます。 |
Parameters | generateMetadata 関数は、以下のパラメータを受け取ります。props - 現在のルートのパラメータを含むオブジェクト。parent - 親ルートセグメントから解決されたmetadataのPromise。 |
Returns | generateMetadata は、1つ以上のmetadataフィールドを含む[Metadata object](https://beta.nextjs.org/docs/api-reference/metadata#metadata-fields)を返す必要があります。 |
Default Fields | routeがmetadataを定義しない場合でも、常に追加される2つのデフォルトのmeta タグがあります。 |
Ordering | metadataは、最終的なpage.js セグメントに最も近いセグメントからルートセグメントまで順に評価されます。 |
Merging | 同じルート内の複数のセグメントからエクスポートされたmetadataオブジェクトは、浅くマージされて、ルートの最終的なmetadata出力を形成します。 |
Overwriting fields | 複数のセグメントからエクスポートされたmetadataのキーが重複する場合、そのキーは順序に基づいて上書きされます。 |
Inheriting fields | 子ルートセグメントで定義されたmetadataは、親ルートセグメントから自動的に継承されます。 |
https://github.com/otoyo/easy-notion-blog/pull/174
import {
NEXT_PUBLIC_URL,
NEXT_PUBLIC_SITE_TITLE,
NEXT_PUBLIC_SITE_DESCRIPTION,
} from '../app/server-constants'
const DocumentHead = ({ title = '', description = '', path = '' }) => {
const elements = path.split('/')
const isSlugPath =
elements[0] === '' && elements[1] === 'blog' && elements.length === 3
const isRootPath = path === '' || path === '/'
let ogImageContent = ''
if (!ogImageContent && NEXT_PUBLIC_URL) {
if (isSlugPath) {
ogImageContent = new URL(
`/api/og-image?slug=${elements[2]}`,
NEXT_PUBLIC_URL
).toString()
} else {
ogImageContent = new URL('/DWB-default.jpg', NEXT_PUBLIC_URL).toString()
}
}
return (
<>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="robots" content="max-image-preview:large" />
<meta charSet="utf-8" />
<title>
{title
? `${title} - ${NEXT_PUBLIC_SITE_TITLE}`
: NEXT_PUBLIC_SITE_TITLE}
</title>
{NEXT_PUBLIC_URL ? (
<link
rel="canonical"
href={new URL(path, NEXT_PUBLIC_URL).toString()}
/>
) : null}
<meta
itemProp="name"
content={
title
? `${title} - ${NEXT_PUBLIC_SITE_TITLE}`
: NEXT_PUBLIC_SITE_TITLE
}
/>
{ogImageContent ? (
<meta itemProp="image" content={ogImageContent} />
) : null}
<meta
name="description"
content={description ? description : NEXT_PUBLIC_SITE_DESCRIPTION}
/>
{NEXT_PUBLIC_URL ? (
<meta
property="og:url"
content={new URL(path, NEXT_PUBLIC_URL).toString()}
/>
) : null}
<meta
property="og:title"
content={title ? title : NEXT_PUBLIC_SITE_TITLE}
/>
<meta
property="og:description"
content={description ? description : NEXT_PUBLIC_SITE_DESCRIPTION}
/>
<meta property="og:site_name" content={NEXT_PUBLIC_SITE_TITLE} />
<meta
property="og:type"
content={isRootPath ? 'website' : isSlugPath ? 'article' : 'blog'}
/>
{ogImageContent ? (
<meta property="og:image" content={ogImageContent} />
) : null}
<meta name="twitter:card" content="summary_large_image" />
{ogImageContent ? (
<meta name="twitter:image" content={ogImageContent} />
) : null}
<meta
name="twitter:title"
content={
title
? `${title} - ${NEXT_PUBLIC_SITE_TITLE}`
: NEXT_PUBLIC_SITE_TITLE
}
/>
<meta
name="twitter:description"
content={description ? description : NEXT_PUBLIC_SITE_DESCRIPTION}
/>
</>
)
}
export default DocumentHead
The Metadata API is used to define application metadata that improves SEO and web sharability.
There are two ways to define Metadata:
metadata
object or a dynamic generateMetadata
function in a layout.js
or page.js
file.// either Static metadata
export const metadata = {
title: '...',
};
// or Dynamic metadata
export async function generateMetadata({ params }) {
return {
title: '...',
};
}
Good to know
- The
metadata
object andgenerateMetadata
function exports are only supported in Server Components.- You cannot export both the
metadata
object andgenerateMetadata
function from the same route segment.
metadata
objectTo define static metadata, export a Metadata
object from a layout.js
or static page.js
file.
layout.tsx|page.tsx
import { Metadata } from 'next';
export const metadata: Metadata = {
title: '...',
description: '...',
};
export default function Page() {}
See the Metadata object reference for a complete list of supported fields.
generateMetadata
functionDynamic metadata depends on dynamic information, such as the current route parameters, external data, or metadata
in parent segments, can be set by exporting a generateMetadata
function that returns a Metadata
object.
動的メタデータは、現在のルートパラメーター、外部データ、または親セグメントの「metadata」などの動的情報に依存し、generateMetadata
関数をエクスポートして、Metadata
オブジェクトを返すように設定することができます。
app/products/[id]/page.tsx
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> {
// read route params
const id = params.id;
// fetch data
const product = await fetch(`https://.../${id}`).then((res) => res.json());
// optionally access and extend (rather than replace) parent metadata
const previousImages = (await parent).openGraph?.images || [];
return {
title: product.title,
openGraph: {
images: ['/some-specific-page-image.jpg', ...previousImages],
},
};
}
export default function Page({ params, searchParams }: Props) {}
generateMetadata
function accepts the following parameters:
props
- An object containing the parameters of the current route:
params
- An object containing the dynamic route parameters object from the root segment down to the segment generateMetadata
is called from.
searchParams
- An object containing the current URL's search params.
parent
- A promise of the resolved metadata from parent route segments.
generateMetadata
should return a Metadata
object containing one or more metadata fields.
Good to know
- If metadata doesn't depend on runtime information, it should be defined using the static
metadata
object rather thangenerateMetadata
.
- runtime:プログラムの実行時、すなわちコンピューターのメモリにプログラムが読み込まれて実行される時間のことです。メタデータが「runtime情報」に依存する場合、その情報は実行時にのみ利用可能であるため、メタデータを定義する際に「generateMetadata」関数を使う必要があります。メタデータが「runtime情報」に依存しない場合、静的な「metadata」オブジェクトを使用して定義することができます。
- When rendering a route, Next.js will automatically deduplicate
fetch
requests for the same data acrossgenerateMetadata
,generateStaticParams
, Layouts, Pages, and Server Components. Reactcache
can be used iffetch
is unavailable.route renderingは、Next.jsでページを作成するときに使用されるプロセスです。これは、ブラウザに表示されるHTMLコンテンツを生成するために、各ページに対して1回実行されます。
route rendering
中には、サーバーとクライアントの両方で実行される2つのフェーズがあります。
- サーバーサイドレンダリング (SSR) - サーバーでレンダリングされ、HTMLを生成するために必要なデータが含まれたページが作成されます。
- クライアントサイドレンダリング (CSR) - ダウンロードされたHTMLがクライアントによって処理され、動的なコンポーネントがレンダリングされます。
route rendering
は、generateMetadata
、generateStaticParams
、レイアウト、ページ、およびサーバーコンポーネント間で同じデータに対する複数のfetch
リクエストを自動的に削除するため、最適化されています。Reactのcache
を使って、fetch
が利用できない場合、手動でキャッシュすることができます。searchParams
are only available inpage.js
segments.
searchParams
は、現在のURLの search params を含むオブジェクトです。例えば、https://example.com?foo=bar&baz=qux
のようなURLの場合、searchParams
オブジェクトは{ "foo": "bar", "baz": "qux" }
となります。searchParams
は、page.js
セグメントでのみ利用可能です。- The
redirect()
andnotFound()
Next.js methods can also be used insidegenerateMetadata
.
redirect()
メソッドは、クライアント側でのリダイレクトをトリガーするために使用されます。このメソッドを使用すると、サーバーサイドで実行された後、ブラウザーにリダイレクトを処理するために、Next.jsが新しいページにクライアント側で遷移します。リダイレクトが必要な場合に、サーバーサイドで処理されるため、SEOの観点からも優れています。リダイレクトは、クライアントがページにアクセスしたときに、別のURLに自動的に転送する機能です。これは、ページのURLを変更した場合や、ユーザーが古いリンクをクリックした場合に便利です。リダイレクトを実行するには、
redirect()
メソッドを使用します。redirect()
メソッドを使うと、サーバー側でリダイレクトを処理し、ブラウザーに新しいページに移動するよう指示します。リダイレクトはSEOの観点からも重要で、ユーザーが正しいページにアクセスできるようにします。
There are two default meta
tags that are always added even if a route doesn't define metadata:
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
Metadata is evaluated in order, starting from the root segment down to the segment closest to the final page.js
segment. For example:
メタデータは、ルートセグメントから最終的な page.js
セグメントに最も近いセグメントまで順番に評価されます。例えば:
app/layout.tsx
(Root Layout)app/blog/layout.tsx
(Nested Blog Layout)app/blog/[slug]/page.tsx
(Blog Page)Following the evaluation order, Metadata objects exported from multiple segments in the same route are shallowly merged together to form the final metadata output of a route. Duplicate keys are replaced based on their ordering.
同じルート内の複数のセグメントからエクスポートされたMetadataオブジェクトは、評価順序に従って浅くマージされ、ルートの最終的なメタデータ出力を形成します。重複するキーは、その順序に基づいて置換されます。
pages/blog/index.js
とpages/blog/[slug].js
は同じルート内にあると考えられます。metadata
オブジェクトやgenerateMetadata
関数が定義された場合、それらは、同じルート内のすべてのページに適用されます。<https://example.com/app/products/[id]>
上記のURLの場合、 app
、 products
、 [id]
はそれぞれセグメントになります。[id]
は、動的なURLセグメントで、異なる id
値によって異なるページを表します。
セグメントの定義は、 pages
ディレクトリー内のフォルダーやファイル名によって決定されます。たとえば、 pages/app.js
ファイルの場合、 app
セグメントが定義されます。同様に、 pages/app/products/[id].js
ファイルの場合、 app
と products
セグメントが定義され、 [id]
は動的なURLセグメントとして定義されます。
This means metadata with nested fields such as openGraph
and robots
that are defined in an earlier segment are overwritten by the last segment to define them.
これは、以前に定義された openGraph
や robots
のような入れ子になったフィールドを持つメタデータが、最後に定義するセグメントによって 上書き されることを意味します。
app/layout.js
export const metadata = {
title: 'Acme',
openGraph: {
title: 'Acme',
description: 'Acme is a...',
},
};
app/blog/page.js
export const metadata = {
title: 'Blog',
openGraph: {
title: 'Blog',
},
};
// Output:
// <title>Blog</title>
// <meta property="og:title" content="Blog" />
In the example above:
title
from app/layout.js
is replaced by title
in app/blog/page.js
.openGraph
fields from app/blog/page.js
are replaced in app/blog/page.js
because app/blog/page.js
sets openGraph
metadata. Note the absence of openGraph.description
.If you'd like to share some nested fields between segments while overwriting others, you can pull them out into a separate variable:
セグメント間で一部のフィールドを上書きしながら他のフィールドを共有したい場合は、それらを別の変数に抜き出すことができます:
app/shared-metadata.js
export const openGraphImage = { images: ['http://...'] };
app/page.js
import { openGraphImage } from './shared-metadata';
export const metadata = {
openGraph: {
...openGraphImage,
title: 'Home'
},
};
app/about/page.js
import { openGraphImage } from '../shared-metadata';
export const metadata = {
openGraph: {
...openGraphImage,
title: 'About',
},
};
In the example above, the OG image is shared between app/layout.js
and app/about/page.js
while the titles are different.
app/layout.js
export const metadata = {
title: 'Acme',
openGraph: {
title: 'Acme',
description: 'Acme is a...',
},
};
app/about/page.js
export const metadata = {
title: 'About',
};
// Output:
// <title>About</title>
// <meta property="og:title" content="Acme" />
// <meta property="og:description" content="Acme is a..." />
Notes
title
from app/layout.js
is replaced by title
in app/about/page.js
.openGraph
fields from app/layout.js
are inherited in app/about/page.js
because app/about/page.js
doesn't set openGraph
metadata.「app/layout.js」のすべての「openGraph」フィールドは、「app/about/page.js」で「openGraph」メタデータが設定されていないため、「app/about/page.js」で継承されます。
title
The title
attribute is used to set the title of the document. It can be defined as a simple string or an optional template object.
export const metadata = {
title: 'Next.js',
};
<title>Next.js</title>
app/layout.tsx
export const metadata = {
title: {
template: '...',
default: '...',
absolute: '...'
},
}
title.template
can be used to add a prefix or a suffix to title
's defined in child route segments.
title.template
は、子ルートセグメントで定義されたtitle
に接頭辞または接尾辞を追加するために使用できます。
%s
の「s」はstringを意味します。
また、Acme | %s
は、%s
が文字列で置き換えられる部分を表します。接頭辞が必要な場合は、この部分に置き換える文字列を指定することができます。
%s
の位置によって接頭辞にも接尾辞にもなるってことかapp/layout.tsx
export const metadata = {
title: {
template: '%s | Acme',
},
}
app/about/page.tsx
export const metadata = {
title: 'About',
}
// Output: <title>About | Acme</title>
Good to know
title.template
applies to child route segments and not the segment it is defined in. This means:
title.template
は、子ルートセグメントに適用され、定義されたセグメント自体には適用されません。つまり、以下の点に注意する必要があります。
title.template
defined inlayout.js
will not apply to atitle
defined in apage.js
of the same segment.
layout.js
で定義されたtitle.template
は、同じセグメント内のpage.js
で定義されたtitle
には適用されません。title.template
defined inpage.js
has no effect because a page is always the terminating segment.
page.js
で定義されたtitle.template
は効果を持ちません。ページは常に終端セグメントであるため、特定のルートのメタデータを決定する際に評価される最後のセグメントです。「terminate」とは、ルートの最後のセグメントを指します。最後のセグメントは常にページであり、特定のルートのメタデータを決定する際に評価される最後のセグメントです。ページが常に終端セグメントであるため、page.jsで定義された
title.template
は効果を持ちません。🤔page.jsでtitle.templateを定義して効果を持たせるにはどうしたらいいんだ?page.jsで
title.template
を適用するには、そのセグメント内でtitle
を定義する必要があります。import { Metadata } from 'next'; export const metadata: Metadata = { title: 'This is the default title', }; export default function Page() { return ( <> <h1>My Page</h1> </> ); }
ここで、
title
を動的に定義する場合、generateMetadata
関数をエクスポートして以下のようにします。import { Metadata } from 'next'; type Props = { params: { id: string }; }; export async function generateMetadata({ params }: Props): Promise<Metadata> { // read route params const id = params.id; return { title: `My Page ${id}`, }; } export default function Page() { return ( <> <h1>My Page</h1> </> ); }
ここで、
title.template
を使用してMy Page {id}
のようなテンプレートを定義し、generateMetadata
関数でid
の値に応じて動的にtitle
を生成することもできます。😲要は、子ファイルでやる場合は親で固定部分を定義して差し替え部分を%s
にしておく。
ファイルに直接titleをいれると差し替え部分が適用される。
その部分の一部を動的に変更したい場合にはパラメータを入れればOK
title.template
has no effect if a route has not defined atitle
ortitle.default
.🤔OGの時のように不足箇所だからといって補充されることはないってことか
title.default
can be used to provide a fallback title to child route segments that don't define a title
.
app/layout.tsx
export const metadata = {
title: {
default: 'Acme',
},
}
app/about/page.tsx
export const metadata = {
}
// Output: <title>Acme</title>
title.absolute
can be used to provide a title that ignores title.template
set in parent segments.
app/layout.tsx
export const metadata = {
title: {
template: '%s | Acme',
},
}
app/about/page.tsx
export const metadata = {
title: {
absolute: 'About',
},
}
// Output: <title>About</title>
Good to know
layout.js
title
(string) andtitle.default
define the default title for child segments (that do not define their owntitle
). It will augmenttitle.template
from the closest parent segment if it exists.title.absolute
defines the default title for child segments. It ignorestitle.template
from parent segments.title.template
defines a new title template for child segments.
page.js
- If a page does not define its own title the closest parents resolved title will be used.
title
(string) defines the routes title. It will augmenttitle.template
from the closest parent segment if it exists.title.absolute
defines the route title. It ignorestitle.template
from parent segments.title.template
has no effect inpage.js
because a page is always the terminating segment of a route.
description
export const metadata = {
description: 'The React Framework for the Web',
};
<meta name="description" content="The React Framework for the Web">
export const metadata = {
generator: 'Next.js',
applicationName: 'Next.js',
referrer: 'origin-when-cross-origin',
keywords: ['Next.js', 'React', 'JavaScript'],
authors: [{ name: 'Seb' }, { name: 'Josh', url: 'https://nextjs.org' }],
colorScheme: 'dark',
creator: 'Jiachi Liu',
publisher: 'Sebastian Markbåge',
formatDetection: {
email: false,
address: false,
telephone: false,
},
};
<meta name="application-name" content="Next.js">
<meta name="author" content="Seb"/>
<link rel="author" href="https://nextjs.org"/>
<meta name="author" content="Josh"/>
<meta name="generator" content="Next.js">
<meta name="keywords" content="Next.js,React,JavaScript">
<meta name="referrer" content="origin-when-cross-origin">
<meta name="color-scheme" content="dark">
<meta name="creator" content="Jiachi Liu">
<meta name="publisher" content="Sebastian Markbåge">
<meta name="format-detection" content="telephone=no, address=no, email=no">
metadataBase
metadataBase
is a convenience option to set a base URL prefix for metadata
fields that require a fully qualified URL.
metadataBase
は、完全修飾URLが必要な metadata
フィールドのベースURLプレフィックスを設定するための便利なオプションです。
metadataBase
allows URL-based metadata
fields defined in the current route segment and below to use a relative path instead of an otherwise required absolute URL.metadataBase
は、現在のルートセグメント以下で定義されたURLベースのmetadata
フィールドが、必要な場合には絶対URLではなく相対パスを使用できるようにします。
metadataBase
to form a fully qualified URL.フィールドの相対パスはmetadataBase
と結合され、完全修飾URLが形成されます。
metadataBase
is automatically populated with a default value.設定されていない場合、metadataBase
は デフォルト値 で 自動的に埋められます。
export const metadata = {
metadataBase: new URL('https://acme.com'),
alternates: {
canonical: '/',
languages: {
'en-US': '/en-US',
'de-DE': '/de-DE',
},
},
openGraph: {
images: '/og-image.png',
},
};
<link rel="canonical" href="https://acme.com">
<link rel="alternate" hreflang="en-US" href="https://nextjs.org/en-US">
<link rel="alternate" hreflang="de-DE" href="https://nextjs.org/de-DE">
<meta property="og:image" content="https://acme.com/og-image.png">
Good to know
metadataBase
is typically set in rootapp/layout.js
to apply to URL-basedmetadata
fields across all routes.- All URL-based
metadata
fields that require absolute URLs can be configured with ametadataBase
option.metadataBase
can contain a sub domain e.g.https://app.acme.com
or base path e.g.https://acme.com/start/from/here
- If a
metadata
field provides an absolute URL,metadataBase
will be ignored.- Using a relative path in a URL-based
metadata
field without configuring ametadataBase
will cause a build error.- Next.js will normalize duplicate slashes between
metadataBase
(e.g.https://acme.com/
) and a relative field (e.g./path
) to a single slash (e.g.https://acme.com/path
)Next.jsは、
metadataBase
(例:https://acme.com/
)と相対フィールド(例:/path
)の間の重複したスラッシュを正規化し、単一のスラッシュ(例:https://acme.com/path
)にします。
metadataBase
を使用する場合、metadata
フィールドで設定されたURLが絶対URLでなくても、相対パスを使用できます。フィールドの相対パスは、metadataBase
と共に完全修飾URLを形成します。つまり、
metadataBase
がhttps://acme.com/
で、相対パスが/path
の場合、最終的なURLはhttps://acme.com/path
に正規化されます。つまり、metadataBase
とフィールドの間にあるスラッシュが重複している場合、Next.jsはこれらのスラッシュを1つのスラッシュに正規化します。💁♀️/blog/tags/page
のようなURLで具体例を示します。
metadataBase
がhttps://example.com
の場合、/blog/tags/page
はhttps://example.com/blog/tags/page
になります。
しかし、metadataBase
がhttps://example.com/
の場合、/blog/tags/page
はhttps://example.com//blog/tags/page
になります。
この場合、Next.jsは重複したスラッシュを1つのスラッシュに正規化し、https://example.com/blog/tags/page
になります。🤔つまり、metaBase末尾にスラッシュがあると生じるダブルスラッシュを解消してくれるってことか
If not configured, metadataBase
has a default value
VERCEL_URL
is detected: https://${process.env.VERCEL_URL}
VERCEL_URL
is set, will always fallback to http://localhost:${process.env.PORT || 3000}
.デフォルト値を上書きする場合、URLを計算するために環境変数を使用することをお勧めします。これにより、ローカル開発、ステージング、本番環境でURLを設定できます。
const NEXT_PUBLIC_URL = process.env.NEXT_PUBLIC_URL
{NEXT_PUBLIC_URL ? (
<link
rel="canonical"
href={new URL(path, NEXT_PUBLIC_URL).toString()}
/>
) : null}
URL composition favors developer intent over default directory traversal semantics.
URLの構成は、デフォルトのディレクトリトラバーサルの意味合いよりも、開発者の意図を優先します。
ディレクトリトラバーサル (directory traversal) :Webアプリケーションでよく起こる脆弱性の一種で、攻撃者がWebサーバーのファイルシステム内のファイルにアクセスできるようになる攻撃です。攻撃者は、Webアプリケーションがサーバー上のファイルを操作するために使用するファイルパスを調べ、ファイルパスを操作して、許可されていないファイルにアクセスします。攻撃者は、ファイルを読み取る、書き換える、削除するなど、悪意のある操作を行うことができます。
metadataBase
and metadata
fields are normalized.「metadataBase」と「metadata」フィールド間の末尾のスラッシュは正規化されます。
metadata
field (that typically would replace the whole URL path) is treated as a "relative" path (starting from the end of metadataBase
).「絶対パス」と「相対パス」の違いは、URLの構成方法によるものです。
For example, given the following metadataBase
:
app/api/layout.tsx
export const metadata = {
metadataBase: new URL('https://acme.com/api'),
};
Any metadata
fields that inherit the above metadataBase
and set their own value will be resolved as follows:
metadata field | Resolved URL |
/ | https://acme.com/api |
./ | https://acme.com/api |
payments | https://acme.com/api/payments |
/payments | https://acme.com/api/payments |
./payments | https://acme.com/api/payments |
../payments | https://acme.com/payments |
https://beta.acme.com/api/payments | https://beta.acme.com/api/payments |
openGraph
export const 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,
},
{
url: 'https://nextjs.org/og-alt.png',
width: 1800,
height: 1600,
alt: 'My custom alt',
},
],
locale: 'en-US',
type: 'website',
},
};
<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:url" content="https://nextjs.org/og.png" />
<meta property="og:image:width" content="800" />
<meta property="og:image:height" content="600" />
<meta property="og:image:url" content="https://nextjs.org/og-alt.png" />
<meta property="og:image:width" content="1800" />
<meta property="og:image:height" content="1600" />
<meta property="og:image:alt" content="My custom alt" />
<meta property="og:type" content="website" />
export const metadata = {
openGraph: {
title: 'Next.js',
description: 'The React Framework for the Web',
type: 'article',
authors: ['Seb', 'Josh'],
},
};
<meta property="og:title" content="Next.js" />
<meta property="og:description" content="The React Framework for the Web" />
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2023-01-01T00:00:00.000Z" />
<meta property="article:author" content="Seb" />
<meta property="article:author" content="Josh" />
Good to know
- It may be more convenient to use the file-based Metadata API for Open Graph images. Rather than having to sync the config export with actual files, the file-based API will automatically generate the correct metadata for you.
Open Graph画像には、ファイルベースのMetadata APIを使用する方が便利かもしれません。設定エクスポートと実際のファイルを同期する必要がなく、ファイルベースのAPIは自動的に正しいメタデータを生成します。
robots
export const metadata = {
robots: {
index: false,
follow: true,
nocache: true,
googleBot: {
index: true,
follow: false,
noimageindex: true,
'max-video-preview': -1,
'max-image-preview': 'large',
'max-snippet': -1,
},
},
};
icons
Note: We recommend using the file-based Metadata API for icons where possible. Rather than having to sync the config export with actual files, the file-based API will automatically generate the correct metadata for you.
icons
を使用すると、アプリケーションのアイコンをブラウザに表示することができます。これにより、ユーザーがWebサイトまたはWebアプリケーションをブックマークするときに、ブックマークにアイコンが表示されます。icons
オブジェクトには、アイコンの各サイズに対する画像のパスを指定できます。例えば、以下のようになります:
export const metadata = {
icons: [
{ src: '/favicon-16x16.png', sizes: '16x16', type: 'image/png' },
{ src: '/favicon-32x32.png', sizes: '32x32', type: 'image/png' },
{ src: '/favicon-48x48.png', sizes: '48x48', type: 'image/png' },
],
};
各 icon
オブジェクトには、以下のプロパティを指定できます。
src
:アイコン画像のパスsizes
:アイコン画像のサイズ。WIDTHxHEIGHT
の形式で指定します。type
:アイコン画像のMIMEタイプ。省略可能です。また、metadata
オブジェクトにはappleTouchIcon
プロパティがあり、iOSのホーム画面に追加する場合に使用されるアイコンを指定することができます。
export const metadata = {
appleTouchIcon: {
src: '/apple-touch-icon.png',
sizes: '180x180',
},
};
export const metadata = {
icons: {
icon: '/icon.png',
shortcut: '/shortcut-icon.png',
apple: '/apple-icon.png',
other: {
rel: 'apple-touch-icon-precomposed',
url: '/apple-touch-icon-precomposed.png',
},
},
};
<link rel="shortcut icon" href="/shortcut-icon.png" />
<link rel="icon" href="/icon.png" />
<link rel="apple-touch-icon" href="/apple-icon.png" />
<link
rel="apple-touch-icon-precomposed"
href="/apple-touch-icon-precomposed.png"
/>
export const metadata = {
icons: {
icon: [{ url: '/icon.png' }, new URL('/icon.png', 'https://example.com')],
shortcut: ['/shortcut-icon.png'],
apple: [
{ url: '/apple-icon.png' },
{ url: '/apple-icon-x3.png', sizes: '180x180', type: 'image/png' },
],
other: [
{
rel: 'apple-touch-icon-precomposed',
url: '/apple-touch-icon-precomposed.png',
},
],
},
};
<link rel="shortcut icon" href="/shortcut-icon.png" />
<link rel="icon" href="/icon.png" />
<link rel="apple-touch-icon" href="/apple-icon.png" />
<link
rel="apple-touch-icon-precomposed"
href="/apple-touch-icon-precomposed.png"
/>
<link rel="icon" href="https://example.com/icon.png" />
<link
rel="apple-touch-icon"
href="/apple-icon-x3.png"
sizes="180x180"
type="image/png"
/>
Note: The
msapplication-*
meta tags are no longer supported in Chromium builds of Microsoft Edge, and thus no longer needed.
themeColor
Learn more about theme-color.
Simple theme color
export const metadata = {
themeColor: 'black',
};
<meta name="theme-color" content="black" />
With media attribute
export const metadata = {
themeColor: [
{ media: '(prefers-color-scheme: light)', color: 'cyan' },
{ media: '(prefers-color-scheme: dark)', color: 'black' },
],
};
<meta name="theme-color" media="(prefers-color-scheme: light)" content="cyan" />
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="black" />
metadata
にthemeColor
を設定すると、ブラウザのアドレスバーの色や、Androidのホーム画面に追加したときのアイコンの背景色が変化します。
manifest
The manifest.json
file is the only file that every extension using WebExtension APIs must contain.
export const metadata = {
manifest: 'https://nextjs.org/manifest.json',
};
twitter
Learn more about the Twitter Card markup reference.
export const metadata = {
twitter: {
card: 'summary_large_image',
title: 'Next.js',
description: 'The React Framework for the Web',
siteId: '1467726470533754880',
creator: '@nextjs',
creatorId: '1467726470533754880',
images: ['https://nextjs.org/og.png'],
},
};
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site:id" content="1467726470533754880" />
<meta name="twitter:creator" content="@nextjs" />
<meta name="twitter:creator:id" content="1467726470533754880" />
<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" />
export const metadata = {
twitter: {
card: 'app',
title: 'Next.js',
description: 'The React Framework for the Web',
siteId: '1467726470533754880',
creator: '@nextjs',
creatorId: '1467726470533754880',
images: {
url: 'https://nextjs.org/og.png',
alt: 'Next.js Logo',
},
app: {
name: 'twitter_app',
id: {
iphone: 'twitter_app://iphone',
ipad: 'twitter_app://ipad',
googleplay: 'twitter_app://googleplay',
},
url: {
iphone: 'https://iphone_url',
ipad: 'https://ipad_url',
},
},
},
};
<meta name="twitter:site:id" content="1467726470533754880" />
<meta name="twitter:creator" content="@nextjs" />
<meta name="twitter:creator:id" content="1467726470533754880" />
<meta name="twitter:title" content="Next.js" />
<meta name="twitter:description" content="The React Framework for the Web" />
<meta name="twitter:card" content="app" />
<meta name="twitter:image" content="https://nextjs.org/og.png" />
<meta name="twitter:image:alt" content="Next.js Logo" />
<meta name="twitter:app:name:iphone" content="twitter_app" />
<meta name="twitter:app:id:iphone" content="twitter_app://iphone" />
<meta name="twitter:app:id:ipad" content="twitter_app://ipad" />
<meta name="twitter:app:id:googleplay" content="twitter_app://googleplay" />
<meta name="twitter:app:url:iphone" content="https://iphone_url" />
<meta name="twitter:app:url:ipad" content="https://ipad_url" />
<meta name="twitter:app:name:ipad" content="twitter_app" />
<meta name="twitter:app:name:googleplay" content="twitter_app" />
viewport
// Note: This is the same values as the default value set
// You likely don't need to change this, but it's included for completeness
export const metadata = {
viewport: {
width: 'device-width',
initialScale: 1,
maximumScale: 1,
},
};
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
metadata
オブジェクトには、viewport
プロパティを設定することができます。これにより、モバイルデバイスでのWebサイトの表示をカスタマイズすることができます。
width
プロパティにはdevice-width
を指定しています。これは、表示領域の幅をデバイスの画面幅に自動的に合わせることを意味します。initialScale
とmaximumScale
プロパティは、初期拡大率と最大拡大率を指定します。
viewport
プロパティには、他にもいくつかの設定があります。たとえば、以下のように設定することができます。
export const metadata = {
viewport: {
width: 'device-width',
initialScale: 1,
maximumScale: 5,
minimumScale: 1,
userScalable: true,
},
};
minimumScale
プロパティを設定することで、最小拡大率を指定することができます。userScalable
プロパティをfalse
にすることで、ユーザーが拡大縮小できないようにすることもできます。
verification
export const metadata = {
verification: {
google: 'google',
yandex: 'yandex',
yahoo: 'yahoo',
other: {
me: ['my-email', 'my-link'],
},
},
};
<meta name="google-site-verification" content="google">
<meta name="y_key" content="yahoo">
<meta name="yandex-verification" content="yandex">
<meta name="me" content="my-email">
<meta name="me" content="my-link">
metadata
オブジェクトには、verification
プロパティを設定することができます。これにより、GoogleやYahooなどのサービスの所有権を確認するためのメタタグを自動的に挿入することができます。
appleWebApp
export const metadata = {
itunes: {
appId: 'myAppStoreID',
appArgument: 'myAppArgument',
},
appleWebApp: {
title: 'Apple Web App',
statusBarStyle: 'black-translucent',
startupImage: [
'/assets/startup/apple-touch-startup-image-768x1004.png',
{
url: '/assets/startup/apple-touch-startup-image-1536x2008.png',
media: '(device-width: 768px) and (device-height: 1024px)',
},
],
},
};
<meta name="apple-itunes-app" content="app-id=myAppStoreID, app-argument=myAppArgument">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-title" content="Apple Web App">
<link href="/assets/startup/apple-touch-startup-image-768x1004.png" rel="apple-touch-startup-image">
<link href="/assets/startup/apple-touch-startup-image-1536x2008.png" media="(device-width: 768px) and (device-height: 1024px)" rel="apple-touch-startup-image">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
metadata
オブジェクトには、appleWebApp
プロパティを設定することができます。これにより、iOSのホーム画面に追加してWebアプリケーションとして使用することができます。
appleWebApp
プロパティには、以下のプロパティを指定できます。
export const metadata = {
appleWebApp: {
title: 'My App',
statusBarStyle: 'default',
startupImage: '/assets/startup.png',
},
};
title
:ホーム画面に追加されたときに表示されるアプリ名statusBarStyle
:ホーム画面に追加されたときのステータスバーのスタイル。default
、black
、black-translucent
のいずれかを指定します。startupImage
:起動時に表示される画像。string
またはobject
の配列を指定します。object
には以下のプロパティを指定できます。url
:画像のURLmedia
:画像が表示される条件を指定するmedia
クエリ。省略可能です。また、metadata
オブジェクトにはitunes
プロパティがあり、App StoreでのアプリのIDや引数を指定することができます。
export const metadata = {
itunes: {
appId: 'myAppStoreID',
appArgument: 'myAppArgument',
},
};
<meta name="apple-itunes-app" content="app-id=myAppStoreID, app-argument=myAppArgument">
alternates
export const metadata = {
alternates: {
canonical: 'https://nextjs.org',
languages: {
'en-US': 'https://nextjs.org/en-US',
'de-DE': 'https://nextjs.org/de-DE',
},
media: {
'only screen and (max-width: 600px)': 'https://nextjs.org/mobile',
},
types: {
'application/rss+xml': 'https://nextjs.org/rss',
},
},
};
<link rel="canonical" href="https://nextjs.org">
<link rel="alternate" hreflang="en-US" href="https://nextjs.org/en-US">
<link rel="alternate" hreflang="de-DE" href="https://nextjs.org/de-DE">
<link rel="alternate" media="only screen and (max-width: 600px)" href="https://nextjs.org/mobile">
<link rel="alternate" type="application/rss+xml" href="https://nextjs.org/rss">
alternates
プロパティを使用すると、Webサイトの「リンクの関係性」を指定することができます。alternates
プロパティには、以下のプロパティを指定できます。
canonical
:WebサイトのカノニカルURLを指定します。languages
:Webサイトの言語バージョンを指定します。{言語コード: URL}
の形式で指定します。media
:メディアクエリに基づいて、異なるバージョンのWebサイトを提供する場合に使用します。types
:Webサイトの別のバージョンを提供するために使用される別のMIMEタイプを指定します。appLinks
export const metadata = {
appLinks: {
ios: {
url: 'https://nextjs.org/ios',
app_store_id: 'app_store_id',
},
android: {
package: 'com.example.android/package',
app_name: 'app_name_android',
},
web: {
url: 'https://nextjs.org/web',
should_fallback: true,
},
},
};
<meta property="al:ios:url" content="https://nextjs.org/ios">
<meta property="al:ios:app_store_id" content="app_store_id">
<meta property="al:android:package" content="com.example.android/package">
<meta property="al:android:app_name" content="app_name_android">
<meta property="al:web:url" content="https://nextjs.org/web">
<meta property="al:web:should_fallback" content="true">
archives
Describes a collection of records, documents, or other materials of historical interest (source).
export const metadata = {
archives: ['https://nextjs.org/13'],
};
<link rel="archives" href="https://nextjs.org/13">
assets
export const metadata = {
assets: ['https://nextjs.org/assets'],
};
<link rel="assets" href="https://nextjs.org/assets">
metadata
にassets
プロパティを設定することで、関連するファイルやリソースを指定することができます。これにより、Webサイトの構造を明確にすることができます。
たとえば、以下のように設定することができます。
export const metadata = {
assets: ['/styles.css', '/script.js'],
};
この場合、/styles.css
と/script.js
がWebサイトに関連するファイルであることを示します。ブラウザはこれらのファイルを事前にダウンロードし、Webサイトの読み込みを高速化することができます。
bookmarks
export const metadata = {
bookmarks: ['https://nextjs.org/13'],
};
<link rel="bookmarks" href="https://nextjs.org/13">
bookmarks
プロパティを使用すると、Webブラウザーのブックマーク機能でWebページをブックマークするときに使用されるデフォルトのURLを指定することができます。
category
export const metadata = {
category: 'technology',
};
<meta name="category" content="technology">
other
All metadata options should be covered using the built-in support. However, there may be custom metadata tags specific to your site, or brand new metadata tags just released. You can use the other
option to render any custom metadata tag.
すべてのメタデータオプションは、組み込みサポートを使用してカバーする必要があります。ただし、サイト固有のカスタムメタデータタグまたは新しくリリースされたメタデータタグがある場合は、 その他
オプションを使用してカスタムメタデータタグをレンダリングできます。
export const metadata = {
other: {
custom: 'meta',
},
};
<meta name="custom" content="meta">
The following metadata types do not currently have built-in support. However, they can still be rendered in the layout or page itself.
Metadata | Recommendation |
<meta http-equiv="..."> | Use appropriate HTTP Headers via redirect() , Middleware, Security Headers |
<base> | Render the tag in the layout or page itself. |
<noscript> | Render the tag in the layout or page itself. |
<style> | Learn more about styling in Next.js. |
<script> | Learn more about using scripts. |
<link rel="stylesheet" /> | import stylesheets directly in the layout or page itself. |
<link rel="preload /> | Use ReactDOM preload method |
<link rel="preconnect" /> | Use ReactDOM preconnect method |
<link rel="dns-prefetch" /> | Use ReactDOM prefetchDNS method |
The <link>
element has a number of rel
keywords that can be used to hint to the browser that a external resource is likely to be needed. The browser uses this information to apply preloading optimizations depending on the keyword.
<link>
要素には、ブラウザに外部リソースが必要であることを示唆するために使用できるいくつかのrel
キーワードがあります。ブラウザは、キーワードに応じてプリロード最適化を適用するためにこの情報を使用します。
While the Metadata API doesn't directly support these hints, you can use new ReactDOM
methods to safely insert them into the <head>
of the document.
Metadata APIはこれらのヒントを直接サポートしていませんが、新しい ReactDOM
メソッドを使用して、これらのヒントをドキュメントの <head>
に安全に挿入することができます。
📍
app/preload-resources.tsx
'use client';
import ReactDOM from 'react-dom';
export function PreloadResources() {
ReactDOM.preload('...', { as: '...' });
ReactDOM.preconnect('...', { crossOrigin: '...' });
ReactDOM.prefetchDNS('...');
return null;
}
<link rel="preload">
Start loading a resource early in the page rendering (browser) lifecycle. MDN Docs.
ReactDOM.preload(href: string, options: { as: string })
<link rel="preconnect">
Preemptively initiate a connection to an origin. MDN Docs.
ReactDOM.preload(href: string, options?: { crossOrigin?: string })
<link rel="dns-prefetch">
Attempt to resolve a domain name before resources get requested. MDN Docs.
ReactDOM.prefetchDNS(href: string)
Good to know
- These methods are currently only supported in Client components.
- Note: Client Components are still Server Side Rendered on initial page load.
- Next.js in-built features such as
next/font
,next/image
andnext/script
automatically handle relevant resource hints.- React 18.3 does not yet include type definitions for
ReactDOM.preload
,ReactDOM.preconnect
, andReactDOM.preconnectDNS
. You can use// @ts-ignore
as a temporary solution to avoid type errors.
You can add type safety to your metadata by using the Metadata
type. If you are using the built-in TypeScript plugin in your IDE, you do not need to manually add the type, but you can still explicitly add it if you want.
metadata
objectimport type { Metadata } from 'next';
export const metadata: Metadata = {
title: 'Next.js',
};
generateMetadata
functionimport type { Metadata } from 'next';
export function generateMetadata(): Metadata {
return {
title: 'Next.js',
};
}
import type { Metadata } from 'next';
export async function generateMetadata(): Promise<Metadata> {
return {
title: 'Next.js',
};
}
import type { Metadata } from 'next';
type Props = {
params: { id: string };
searchParams: { [key: string]: string | string[] | undefined };
};
export function generateMetadata({ params, searchParams }: Props): Metadata {
return {
title: 'Next.js',
};
}
export default function Page({ params, searchParams }: Props) {}
import type { Metadata, ResolvingMetadata } from 'next';
export async function generateMetadata(
{ params, searchParams }: Props,
parent: ResolvingMetadata,
): Promise<Metadata> {
return {
title: 'Next.js',
};
}
For JavaScript projects, you can use JSDoc to add type safety.
/** @type {import("next").Metadata} */
export const metadata = {
title: 'Next.js',
};
File-based metadata can be defined by adding special metadata files to route segments.
Each file convention can be defined using a static file e.g. app/opengraph-image.jpg
, or a dynamic variant that uses code to generate the file e.g. app/opengraph-image.js
.
Once a file is defined, Next.js will automatically serve the file (with hashes in production for caching) and update the relevant head elements with the correct metadata, such as the asset's URL, file type, and image size.
Good to know
- File-based metadata has the higher priority and will override any config-based metadata. e.g.
app/opengraph-image.jpg
will override ametadata.opengraph.image
export inapp/layout.js
.
Add an icon
file to the root segment of the app
directory to set an icon for your application.
icon
Add a favicon.ico
, icon.(ico|jpg|jpeg|png|svg)
, or apple-icon.(jpg|jpeg|png|svg)
file to the root segment.
Add a icon.(js|ts|tsx)
or apple-icon.(js|ts|tsx)
file that default exports a function that returns Blob
| ArrayBuffer
| TypedArray
| DataView
| ReadableStream
| Response
.
The easiest way to generate an image is to use the ImageReponse API from next/server
.
You can optionally configure the icon's image metadata by exporting sizes
and contentType
variables from the file.
import { ImageResponse } from 'next/server';
export const size = {
width: 32,
height: 32,
};
export const contentType = 'image/png';
export const runtime = 'edge';
export default function icon() {
return new ImageResponse(
(
<div
style={{
fontSize: 24,
background: 'black',
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: 'white',
}}
>
A
</div>
),
size,
);
}
Good to know
- You can set multiple icons for your application by adding a number suffix to the file name. For example,
icon1.(jpg|tsx)
,icon2.(jpg|tsx)
, etc. Numbered files will sort lexically.sizes="any"
is added tofavicon.ico
output to avoid a browser bug where an.ico
icon is favored over.svg
.- You cannot dynamically generate a
favicon
file.
Add an opengraph-image
or twitter-image
file to a route segment to set an Open Graph or Twitter image for that segment.
Add an opengraph-image.(jpg|jpeg|png|gif)
or twitter-image.(jpg|jpeg|png|gif)
file to any route segment.
Add an opengraph-image.(js|ts|tsx)
or twitter-image.(js|ts|tsx)
file that default exports a function that returns Blob
| ArrayBuffer
| TypedArray
| DataView
| ReadableStream
| Response
.
The easiest way to generate an image is to use the ImageReponse API from next/server
.
You can optionally configure the image's metadata by exporting alt
, size
, and contentType
variables from the file.
app/about/opengraph-image.tsx
import { ImageResponse } from 'next/server';
export const alt = 'About Acme';
export const size = {
width: 1200,
height: 630,
};
export const contentType = 'image/png';
export default function og() {
return new ImageResponse(
(
<div
style={{
fontSize: 128,
background: 'white',
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
About Acme
</div>
),
size,
);
}
Good to know
- You can set multiple Open Graph images for a route segment by adding a number suffix to the file name. For example,
opengraph-image1.(jpg|tsx)
,opengraph-image2.(jpg|tsx)
, etc. Numbered files will sort lexically within their given segment.
Add or generate a robots.txt
file that matches the Robots Exclusion Standard in the root of app
directory to tell search engine crawlers which URLs they can access on your site.
robots.txt
app/robots.txt
User-Agent: *
Allow: /
Disallow: /private/
Sitemap: https://acme.com/sitemap.xml
Add a robots.js
or robots.ts
file that returns a Robots
object.
app/robots.ts
import { MetadataRoute } from 'next';
export default function robots(): MetadataRoute.Robots {
return {
rules: {
userAgent: '*',
allow: '/',
disallow: '/private/',
},
sitemap: 'https://acme.com/sitemap.xml',
};
}
type Robots = {
rules:
| {
userAgent?: string | string[];
allow?: string | string[];
disallow?: string | string[];
crawlDelay?: number;
}
| Array<{
userAgent: string | string[];
allow?: string | string[];
disallow?: string | string[];
crawlDelay?: number;
}>;
sitemap?: string | string[];
host?: string;
};
Add or generate a sitemap.xml
file that matches the Sitemaps XML format in the root of app
directory to help search engine crawlers crawl your site more efficiently.
sitemap.xml
app/sitemap.xml
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://acme.com</loc>
<lastmod>2023-04-06T15:02:24.021Z</lastmod>
</url>
<url>
<loc>https://acme.com/about</loc>
<lastmod>2023-04-06T15:02:24.021Z</lastmod>
</url>
<url>
<loc>https://acme.com/blog</loc>
<lastmod>2023-04-06T15:02:24.021Z</lastmod>
</url></urlset>
Add a sitemap.js
or sitemap.ts
file that returns Sitemap
.
app/sitemap.ts
import { MetadataRoute } from 'next';
export default function sitemap(): MetadataRoute.Sitemap {
return [
{
url: 'https://acme.com',
lastModified: new Date(),
},
{
url: 'https://acme.com/about',
lastModified: new Date(),
},
{
url: 'https://acme.com/blog',
lastModified: new Date(),
},
];
}
type Sitemap = Array<{
url: string;
lastModified?: string | Date;
}>;
Good to know
- In the future we will support multiple sitemaps and sitemap indexes.