head.js (deprecated)

Note: Built-in support for SEO through metadata is available on 13.2. This replaces the previous head.js implementation. The head.js special file was deprecated in 13.2 and will be removed in a future version. View Migration Guide.

Migration Guide

Instead of using a special head.js file, metadata can be set directly inside a layout.js or page.js file by exporting a static metadata object or dynamic generateMetadata function.

Simple metadata

The metadata object can be used to set static metadata for a route segment.

Before: head.js API

app/head.tsx
export default function Head() {
  return (
    <>
      <title>My Title</title>
    </>
  );
}

After: metadata API

app/layout.tsx|page.tsx
export const metadata = {
  title: 'My Title',
}

export default function Layout() {}

Dynamic metadata

The generateMetadata function can be used to fetch data and generate metadata based on the current segment dynamic params.

Before: head.js API

app/post/[slug]/head.tsx
export default async function Head({
  params,
}: {
  params: { slug: string };
}) {
  const post = await fetch(`https://.../${params.slug}`).then((res) =>
    res.json(),
  );

  return (
    <>
      <title>{post.title}</title>
    </>
  );
}

After: metadata API

app/post/[slug]/page.tsx
export async function generateMetadata({
  params,
}: {
  params: { slug: string };
}) {
  const post = await fetch(`https://.../${params.slug}`).then((res) =>
    res.json(),
  );

  return {
    title: post.title,
  };
}

export default function PostPage() {}

Open Graph and Robots

The metadata API has built-in support for Open Graph and Robots.

Before: head.js API

head.tsx
export default function Head() {
  return (
    <>
      <meta property="og:title" content="Next.js" />
      <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 name="robots" content="index" />
    </>
  );
}

After: metadata API

layout.tsx|page.tsx
export const metadata = {
  openGraph: {
    title: 'Next.js',
    url: 'https://nextjs.org',
    images: [
      {
        url: 'https://nextjs.org/og.png',
        width: 800,
        height: 600,
      },
    ],
  },
  robots: {
    index: true,
  }
}

Global / Shared Metadata

The metadata API has better support for shared or global metadata.

  • In the head.js API, nested head.js files do not inherit or merge tags from parent segments. This meant, you had to import a shared component for tags you wanted shared across multiple segments.
  • In the metadata API, defined metadata objects are shallowly merged together to form the final metadata output. Learn more about shared metadata.
app/default-tags.tsx
export default function DefaultTags() {
  return (
    <>
      <meta name="theme-color" content="#111111" />
    </>
  );
}
app/head.tsx
// Shared metadata has to be explicitly included
import DefaultTags from './default-tags';

export default function Head() {
  return (
    <>
      <DefaultTags />
      <title>My Homepage</title>
    </>
  );
}
app/dashboard/head.tsx
// Shared metadata has to be explicitly included
import DefaultTags from '../default-tags';

export default function Head() {
  return (
    <>
      <DefaultTags />
      <title>My Dashboard</title>
    </>
  );
}

After: metadata API

app/layout.tsx
// Metadata defined in a parent segment will be
// shared (merged) into all child segments.
export const metadata = {
   themeColor: '#111',
};

export default function Layout() {}

Good to know

  • The <head> HTML tag no longer needs to be set in a root layout.js.
  • The viewport and charset meta tags are now set by default

API Reference (deprecated)

Note: In Next.js 13.2, head.js was deprecated and replaced with built-in support for SEO through the metadata API. The API Reference is kept available to help maintenance.

The head.js special file allows you to configure the <head> tag for a route segment.

app/blog/[slug]/head.tsx
export default function Head({ params }: { params: { slug: string } }) {
  return (
    <>
      <title>My Page</title>
    </>
  );
}

Good to know:

Props

params (optional)

The dynamic route parameters object from the root segment down to that head.

ExampleURLparams
app/shop/[slug]/head.js/shop/1{ slug: '1' }
app/shop/[category]/[item]/head.js/shop/1/2{ category: '1', item: '2' }
app/shop/[...slug]/head.js/shop/1/2{ slug: ['1', '2']

Sharing tags across multiple routes

The current active route segment will use the nearest parent head.js file. For example:

RouteSelected head.js
/app/head.js
/dashboardapp/dashboard/head.js (if it exists)
/dashboard/settingsapp/dashboard/settings/head.js (if it exists)

Nested head.js files do not inherit or merge tags from head.js files higher up in the tree. This means, if a tag is not returned in the currently selected head.js file, it will not be rendered in the document's <head> element.

You can create a shared component to define tags that are shared between multiple routes. For example:

app/default-tags.tsx
export default function DefaultTags() {
  return (
    <>
      <meta name="viewport" content="width=device-width, initial-scale=1" />
      <link href="/favicon.ico" rel="shortcut icon" />
    </>
  );
}

The shared component can be imported wherever you need to use the tags:

app/dashboard/head.tsx
import DefaultTags from '../default-tags';

export default function Head() {
  return (
    <>
      <DefaultTags />
      <title>My Dashboard</title>
    </>
  );
}

Data fetching and Dynamic Tags

You can fetch data inside head.js to create dynamic titles and meta tags. For example:

app/post/[slug]/head.tsx
async function getPost(slug) {
  const res = await fetch('...');
  return res.json();
}

export default async function Head({ params }) {
  const post = await getPost(params.slug);

  return (
    <>
      <title>{post.title}</title>
    </>
  )
}

Good to know:

  • When rendering a route, Next.js will automatically dedupe requests for the same data across head.js, generateStaticParams, generateMetadata, Layouts, Pages, and Server Components.
  • Next.js will wait for data fetching inside head.js to complete before streaming UI to the client. This guarantees the first part of a streamed response includes <head> tags.

Supported <head> tags

head.js should only return to the following tags:

  • <title>
  • <meta>
  • <link> (only if it has the precedence attribute)
  • <script> (only if it has the async attribute)

Exceptions:

  • You cannot use synchronous inline <script> in head.js. Use next/script or async scripts. Alternatively, place them in the <head> element of your root layout.
  • You cannot use <noscript> in head.js. Place it in the <head> element of your root layout.
  • If you want to manually place <link rel="stylesheet" />, it needs a precedence field which is a new React-specific attribute <link rel="stylesheet" precedence="default" />.