Back to Blog
Lesson 36 of the Next.js: Build Full-Stack Apps with the App Router course
Next.jsAugust 23, 20264 min read

Advanced Metadata Patterns: Scaling SEO in Next.js

Learn to master SEO scalability in Next.js using metadata base URLs and template strings. Build a robust, maintainable content strategy for your blog.

Next.jsSEOMetadataWeb DevelopmentApp Router

Previously in this course, we explored generating dynamic metadata by exporting generateMetadata functions. While that handles individual pages, managing SEO for a growing application requires a more architectural approach. In this lesson, we’ll move from per-page objects to a scalable system using metadata templates and base URLs.

Defining Your Metadata Base

In production, search engines need to know the absolute URL of your site to correctly index your pages and build canonical links. If your metadata only contains relative paths, you risk broken canonicals and SEO dilution.

Next.js provides a clean way to handle this via the metadataBase property in your root layout. This tells Next.js how to resolve relative URLs into absolute ones.

In your app/layout.js, add the metadataBase property to your metadata object:

JAVASCRIPT
// app/layout.js
export const metadata = {
  metadataBase: new URL(CE9178">'https://your-production-domain.com'),
  title: {
    default: CE9178">'My Awesome Blog',
    template: CE9178">'%s | My Awesome Blog',
  },
  description: CE9178">'A blog about building full-stack apps with Next.js.',
};

By setting this once in the root, every relative link you use in your page-level metadata (like an Open Graph image path) will automatically be prefixed with this base URL.

Using Template Strings for Consistency

Notice the title object above? This is the gold standard for SEO scalability. Instead of hardcoding every title, we use the template property.

When you define a template with %s, Next.js takes the title defined in a specific page and injects it into that string. For example, if your blog post page has title: 'Learning Next.js', the final rendered title becomes Learning Next.js | My Awesome Blog.

This pattern ensures that:

  1. Your brand name is always present.
  2. The page-specific content comes first (which is better for user experience in browser tabs).
  3. You only need to update the brand name in one file if you ever rebrand.

Implementing Default SEO Configurations

To keep your codebase clean, you should avoid repeating common metadata (like Twitter card types or robots settings) on every single page. By combining metadataBase and template with a shared metadata object, you create a "source of truth."

If you need to share complex configuration, define it in a separate constants file or a shared component:

JAVASCRIPT
// lib/metadata.js
export const sharedMetadata = {
  twitter: {
    card: CE9178">'summary_large_image',
    site: CE9178">'@yourhandle',
  },
  openGraph: {
    type: CE9178">'website',
    locale: CE9178">'en_US',
  }
};

Then, spread this into your page-level metadata:

JAVASCRIPT
// app/blog/[slug]/page.js
import { sharedMetadata } from CE9178">'@/lib/metadata';

export async function generateMetadata({ params }) {
  const post = await getPost(params.slug);
  return {
    ...sharedMetadata,
    title: post.title,
    description: post.excerpt,
    openGraph: {
      ...sharedMetadata.openGraph,
      title: post.title,
    }
  };
}

Hands-on Exercise: Apply the Template

  1. Open your app/layout.js.
  2. Update the metadata object to include a metadataBase pointing to your local development URL (e.g., http://localhost:3000).
  3. Refactor your title into the default and template object structure shown above.
  4. Visit one of your dynamic blog post pages and inspect the <title> tag in your browser's "Elements" tab to confirm the template is being applied.

Common Pitfalls

  • Forgetting metadataBase: If you use relative URLs in Open Graph images without a metadataBase, social media scrapers will fail to find your images, resulting in blank previews.
  • Over-nesting Metadata: Next.js merges metadata objects, but later definitions (nested pages) override parent ones. Don't try to merge deeply nested objects manually; let the framework handle the shallow merge.
  • Hardcoding Brand Names: Avoid adding your site name to every page's title object. Use the %s template pattern to keep it DRY (Don't Repeat Yourself).

FAQ

Why use metadataBase instead of hardcoding full URLs? Hardcoding URLs makes it difficult to switch between staging, preview, and production environments. metadataBase allows you to define the environment URL once.

Can I override the template? Yes. If you provide a raw string as title in a page metadata object, it will ignore the template. You can also pass an object to specify template: null if you want to bypass the global template for a specific page.

Recap

We've established a robust SEO foundation by centralizing our metadataBase, enforcing consistency with title templates, and using shared objects to avoid duplication. This approach ensures your blog remains indexable and professional as you add more content.

Up next: Handling Large Data Sets — we'll learn how to keep your application performant as your database grows.

Similar Posts