docs

Layouts

Layouts in Next.js

Definition (from Next.js documentation):

Layouts are used to define UI that is shared across multiple pages. They allow you to create consistent experiences by reusing the same structure (like headers, footers, and sidebars) across your application.

A layout can wrap one or more pages in the app and can be nested, enabling the creation of hierarchical layouts. Layouts are designed to be Server Components by default in Next.js, which makes them efficient for performance and static generation.

Example: Basic Layout

Folder structure:

app/
  ├── layout.tsx     // Global layout
  ├── page.tsx       // Home page
  ├── about/
  │   ├── page.tsx   // About page
export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        <header>My Website Header</header>
        <main>{children}</main>
        <footer>My Website Footer</footer>
      </body>
    </html>
  );
}

This layout wraps all pages in the app and applies a common structure: a header, main content area, and footer.

export default function HomePage() {
  return <h1>Welcome to the Home Page</h1>;
}

When visiting /, the content from HomePage will be displayed within the layout structure.

Key Points:


Nested Layouts in Next.js

Definition:

Nested Layouts allow you to create multiple layers of layouts, where each layout applies to a subset of pages. A nested layout wraps another layout, enabling hierarchical designs and shared sections at different levels.

Nested layouts are especially useful when you need to apply different layouts to different parts of the site, such as having a main layout for the entire site and a nested layout for specific sections.

Example: Nested Layouts

Folder structure:

app/
  ├── layout.tsx                // Root layout
  ├── dashboard/
  │   ├── layout.tsx            // Dashboard layout
  │   ├── settings/
  │   │   ├── page.tsx          // Settings page
  │   ├── profile/
  │       ├── page.tsx          // Profile page
export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        <header>My Website Header</header>
        <main>{children}</main>
      </body>
    </html>
  );
}
export default function DashboardLayout({ children }) {
  return (
    <div>
      <nav>Dashboard Sidebar</nav>
      <div>{children}</div>
    </div>
  );
}
export default function SettingsPage() {
  return <h1>Dashboard Settings</h1>;
}

When navigating to /dashboard/settings, the following layout structure will be rendered:

  1. The Root Layout (app/layout.tsx) wraps the entire page.
  2. The Dashboard Layout (app/dashboard/layout.tsx) wraps the SettingsPage, applying the sidebar to all dashboard-related pages.

Key Points:


Route Group Layouts in Next.js

Definition (from Next.js documentation):

Route Groups allow you to group routes together without affecting the URL structure. You can define layouts that apply to certain groups of pages using route groups.

Route Group Layouts are similar to normal layouts, but they apply to specific groups of routes that are organized into folders that don’t affect the URL.

Example: Route Group Layouts

Folder structure:

app/
  ├── (marketing)/
  │   ├── layout.tsx            // Layout for marketing pages
  │   ├── home/
  │   │   ├── page.tsx          // Home page (accessible at '/')
  │   ├── about/
  │       ├── page.tsx          // About page (accessible at '/about')
  ├── (dashboard)/
  │   ├── layout.tsx            // Layout for dashboard pages
  │   ├── settings/
  │       ├── page.tsx          // Settings page (accessible at '/settings')
export default function MarketingLayout({ children }) {
  return (
    <div>
      <header>Marketing Header</header>
      <main>{children}</main>
    </div>
  );
}
export default function DashboardLayout({ children }) {
  return (
    <div>
      <nav>Dashboard Navigation</nav>
      <main>{children}</main>
    </div>
  );
}

In this example:

Key Points:


Summary:

  1. Layouts: Shared structure for multiple pages (e.g., header, footer) and are defined as layout.tsx in any directory.
  2. Nested Layouts: Layouts that are applied to subdirectories within other layouts, allowing for hierarchical designs.
  3. Route Group Layouts: Layouts applied to routes organized under route groups (() folders) without affecting the URL structure.

Each of these layout types provides a way to modularize your Next.js application, making it scalable and easy to maintain.

Metadata

Next.js has a robust metadata API that allows developers to define meta tags for SEO, social media sharing, and other purposes at the page level. Starting from Next.js 13, Next.js uses App Router which introduces a new way to define static, dynamic, and async metadata.

Metadata in Next.js helps improve SEO and the overall performance of your app by controlling page title, description, Open Graph metadata for social sharing, and more.

Types of Metadata in Next.js

  1. Static Metadata: Metadata defined at build time and remains constant.
  2. Dynamic Metadata: Metadata that can change based on runtime data, e.g., from a request.
  3. Async Metadata: Metadata that can be fetched asynchronously, for example, from a database or external API.

Each type of metadata is integrated into Next.js’s App Router.


1. Static Metadata

Static metadata is defined in a component at build time. This means that it remains the same throughout the application lifecycle and does not rely on any runtime data.

Example:

Static metadata is usually defined inside the metadata object exported from a component file, like layout.tsx or page.tsx. Here’s how you can define static metadata:

// app/page.tsx

export const metadata = {
  title: "Home | My Next.js App",
  description: "Welcome to the home page of my Next.js app",
};

Key points:


2. Dynamic Metadata

Dynamic metadata allows you to set metadata based on the runtime state or request. This is important when your page’s content and metadata depend on dynamic input, such as route parameters or query strings.

Dynamic metadata can be generated based on props, params, or even cookies.

Example:

Imagine a blog where the page’s metadata depends on the slug (unique identifier) of the blog post:

// app/blog/[slug]/page.tsx

import { Metadata } from "next";

export async function generateMetadata({
  params,
}: {
  params: { slug: string };
}): Promise<Metadata> {
  const post = await getPostBySlug(params.slug);

  return {
    title: post.title,
    description: post.excerpt,
  };
}

export default function BlogPost({ params }: { params: { slug: string } }) {
  return <h1>{params.slug}</h1>;
}

Key points:


3. Async Metadata

Async metadata in Next.js lets you fetch metadata asynchronously, often from external APIs or databases. This is beneficial when metadata depends on data that is fetched during runtime.

In Next.js 13, generateMetadata can also be an asynchronous function to allow for async data fetching inside the metadata generation process.

Example:

Consider a page where the metadata is fetched from an external API, such as a headless CMS:

// app/product/[id]/page.tsx

import { Metadata } from "next";

async function fetchProductData(id: string) {
  const res = await fetch(`https://api.example.com/products/${id}`);
  return res.json();
}

export async function generateMetadata({
  params,
}: {
  params: { id: string };
}): Promise<Metadata> {
  const product = await fetchProductData(params.id);

  return {
    title: product.name,
    description: product.description,
    openGraph: {
      title: product.name,
      description: product.description,
      images: [
        {
          url: product.image,
        },
      ],
    },
  };
}

export default function ProductPage({ params }: { params: { id: string } }) {
  const product = fetchProductData(params.id);

  return (
    <div>
      <h1>{product.name}</h1>
      <p>{product.description}</p>
    </div>
  );
}

Key points:


How to Structure Metadata

1. Basic Metadata Fields:

Next.js offers several commonly used metadata fields that you can include in your metadata object.

export const metadata = {
  title: "My Page Title",
  description: "This is a description of my page",
  keywords: ["next.js", "seo", "metadata"],
  author: "John Doe",
  viewport: "width=device-width, initial-scale=1.0",
};

2. Open Graph Metadata:

For social media optimization (Facebook, Twitter, etc.), Open Graph metadata is essential.

export const metadata = {
  openGraph: {
    title: "My Awesome Site",
    description: "A short description of my site",
    url: "https://mysite.com",
    siteName: "MySite",
    images: [
      {
        url: "https://mysite.com/og-image.jpg",
        width: 800,
        height: 600,
        alt: "Og Image Alt",
      },
    ],
    locale: "en_US",
    type: "website",
  },
};

3. Twitter Metadata:

Twitter-specific metadata can also be added:

export const metadata = {
  twitter: {
    card: "summary_large_image",
    site: "@site_account",
    creator: "@individual_account",
    title: "Twitter Title",
    description: "Twitter Description",
    images: ["https://example.com/image.jpg"],
  },
};

Using Metadata in Layouts

In Next.js, you can define metadata for entire sections of your app by exporting metadata from the layout.tsx file. This is beneficial when the metadata is shared across multiple pages, such as in an eCommerce site where all product pages share common metadata.

// app/products/layout.tsx

export const metadata = {
  title: "Products - My eCommerce Site",
  description: "Browse our wide selection of products.",
};

export default function ProductsLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return <>{children}</>;
}

Combining Metadata

You can combine static, dynamic, and async metadata together. For example, you may want to define static metadata for common pages like the homepage but have dynamic metadata for product pages and async metadata for fetching product data.

export async function generateMetadata({
  params,
}: {
  params: { id: string };
}): Promise<Metadata> {
  const staticMetadata = {
    title: "Static Title",
    description: "This is a static description",
  };

  const product = await fetchProductData(params.id); // Async fetching data

  return {
    ...staticMetadata,
    title: `${staticMetadata.title} | ${product.name}`,
    description: product.description,
    openGraph: {
      title: product.name,
      description: product.description,
      images: [
        {
          url: product.image,
        },
      ],
    },
  };
}

This combination gives you flexibility to manage SEO metadata efficiently and effectively.


Summary:

Next.js’s metadata API is a powerful tool to enhance your app’s SEO, social media sharing, and more. The combination of static, dynamic, and async metadata allows for great flexibility across different types of applications.

Title Metadata

In Next.js, managing the page title and metadata is essential for SEO and a great user experience. Starting from Next.js version 13.3, it introduced the metadata API, which allows for more flexibility and control over how metadata (like title, description, etc.) is defined for pages and components.

When working with the title metadata, there are three important properties:

1. default Property:

2. absolute Property:

3. template Property:


Example

Here’s how you can use the title metadata in Next.js with default, absolute, and template:

// app/layout.js (in Next.js app directory structure)

export const metadata = {
  title: {
    default: "My Website",
    template: "%s | My Website",
    absolute: false, // If true, it will ignore the template and default.
  },
};

// For a specific page in app directory (e.g., app/about/page.js):

export const metadata = {
  title: "About Us",
};

// Final output on this page would be "About Us | My Website"

How Each Property Works:

  1. default:

    • This is the fallback title when no other title is provided. For example, if a page doesn’t specify a title, it would just show “My Website.”
  2. template:

    • This string is used to format the title. The %s will be replaced with the actual page title.
    • For example, if a page has a title of About Us, the final title in the HTML will be: About Us | My Website.
  3. absolute:

    • When set to true, the title will be exactly what you specify on the page, without any default or template applied.
    • If absolute is true, the page with a title of About Us will just have About Us in the title tag, without the | My Website suffix.

Example Output in the <head>:

  1. With Template:

    <title>About Us | My Website</title>
    
  2. With Absolute Title:

    // app/contact/page.js
    export const metadata = {
      title: { absolute: true, default: "Contact Us" },
    };
    
    <title>Contact Us</title>