---
title: "Internal Linking Strategy for Nuxt Sites"
description: "Use NuxtLink, topic hubs, breadcrumbs, and link audits to make useful pages easier to discover and navigate."
canonical_url: "https://nuxtseo.com/learn-seo/nuxt/routes-and-rendering/internal-linking"
last_updated: "2026-10-05"
---

> Index of every page on this site: [llms.txt](https://nuxtseo.com/llms.txt)

::key-takeaways
- Keep useful pages reachable through crawlable links; Google does not document a universal three-click limit
- `<NuxtLink>`{lang="html"} renders a standard `<a>`{lang="html"} tag, providing a crawlable href
- Hub and spoke architecture is one useful pattern for topic clusters, connecting a pillar page to related child pages and back
- Orphan pages lack internal links. Add useful crawlable links without assuming sitemap submission guarantees indexing
- Google uses crawlable links to discover pages and understand their context
::

[Google recommends crawlable links](https://developers.google.com/search/docs/crawling-indexing/links-crawlable) with descriptive anchor text. They help readers navigate and help Google discover pages and understand their context.

## Why Internal Links Matter

Internal links provide discovery paths, navigation, and context for related pages.

### Crawl Depth

[Google uses crawlable links to discover pages](https://developers.google.com/search/docs/crawling-indexing/links-crawlable). Crawl frequency depends on multiple signals; link depth alone does not establish a daily or weekly schedule.

```
Homepage (depth 0)
├── /features (depth 1)
│   ├── /features/editor (depth 2)
│   │   └── /features/editor/plugins (depth 3)
│   │       └── /features/editor/plugins/markdown (depth 4)
```

### PageRank Distribution

Links are one input to Google’s ranking systems. Google does not publish a formula for the weight of each internal link. Put useful links where readers can find them.

### Topical Authority

Related links help readers find supporting material and help Google understand page context. A topic cluster does not guarantee higher rankings.

**Comparison: pages with and without internal links**

| Aspect     | Pages With Internal Links   | Orphan Pages                       |
| ---------- | --------------------------- | ---------------------------------- |
| Discovery  | Crawlable links expose URLs | Missing links can hinder discovery |
| Navigation | Related links help readers  | Isolated pages are harder to reach |

## Hub and Spoke Architecture

The hub and spoke model is one useful internal linking pattern for content sites. A **hub page** (pillar page) serves as the central entry point for a topic. **Spoke pages** cover subtopics in depth. The hub links to every spoke, and every spoke links back to the hub and to sibling spokes.

Link related spoke pages when that connection helps readers continue their task.

This integration excerpt requires a configured `content` Content collection with path, title, and description fields. It lists matching documents, not every possible generated route:

```vue [pages/features/index.vue]
<script setup lang="ts">
const { data: features } = await useAsyncData('features', () =>
  queryCollection('content')
    .where('path', 'LIKE', '/features/%')
    .where('path', '<>', '/features')
    .order('title', 'ASC')
    .all())

useSeoMeta({
  title: 'Features Overview',
  description: 'Explore all features including color extraction, font detection, and performance analysis.'
})
</script>

<template>
  <div>
    <h1>Features</h1>
    <p>Everything our platform offers, organized by capability.</p>

    <div class="grid grid-cols-1 md:grid-cols-2 gap-6 mt-8">
      <NuxtLink
        v-for="feature in features"
        :key="feature.path"
        :to="feature.path"
        class="block p-6 border border-muted rounded-lg hover:bg-muted transition-colors"
      >
        <h2 class="text-lg font-semibold">
          {{ feature.title }}
        </h2>
        <p class="text-muted mt-2">
          {{ feature.description }}
        </p>
      </NuxtLink>
    </div>
  </div>
</template>
```

Each spoke page should include a link back to the hub and to related spokes:

```vue [pages/features/color-extraction.vue]
<script setup lang="ts">
useSeoMeta({
  title: 'Color Extraction',
  description: 'Extract dominant colors from any image with our color extraction engine.'
})
</script>

<template>
  <article>
    <NuxtLink to="/features" class="text-primary mb-4 inline-block">
      ← Back to all features
    </NuxtLink>

    <h1>Color Extraction</h1>
    <p>Our color extraction engine identifies dominant colors...</p>

    <!-- Contextual links to sibling spokes -->
    <p>
      Color extraction pairs well with
      <NuxtLink to="/features/font-detection">
        font detection
      </NuxtLink>
      for complete design analysis. See how it integrates with our
      <NuxtLink to="/features/performance-analysis">
        performance analysis
      </NuxtLink>
      pipeline.
    </p>
  </article>
</template>
```

If the homepage links to this hub, its listed spokes are two links away. Verify the actual navigation and collection coverage.

## Implementing with NuxtLink

`<NuxtLink>`{lang="html"} is the correct way to create internal links in Nuxt. It renders a standard `<a href="...">`{lang="html"} tag that search engines can follow, while also enabling client-side navigation for users.

### Anchor Text Matters

The clickable text inside your link (anchor text) tells Google what the destination page is about. [Google recommends](https://developers.google.com/search/docs/crawling-indexing/links-crawlable) descriptive, natural anchor text and warns against cramming exact-match keywords.

::code-group
```vue [✅ Correct]
<template>
  <p>
    See our guide on
    <NuxtLink to="/blog/nuxt-meta-tags">
      configuring meta tags in Nuxt
    </NuxtLink>
    for detailed implementation steps.
  </p>

  <p>
    The
    <NuxtLink to="/features/color-extraction">
      color extraction feature
    </NuxtLink>
    supports PNG, JPEG, and WebP formats.
  </p>
</template>
```

```vue [❌ Wrong]
<template>
  <p>
    For meta tags in Nuxt,
    <NuxtLink to="/blog/nuxt-meta-tags">
      this link
    </NuxtLink>.
  </p>

  <p>
    Learn more about this feature
    <NuxtLink to="/features/color-extraction">
      on this page
    </NuxtLink>.
  </p>
</template>
```
::

“Click here” and “here” are less descriptive than “configuring meta tags in Nuxt.” Surrounding text also provides context.

### Breadcrumb Navigation

Breadcrumb links help readers navigate. Valid breadcrumb structured data can make a page eligible for Google’s supported breadcrumb appearance; display is not guaranteed. Use `defineBreadcrumb()`{lang="ts"} from `nuxt-schema-org`:

```vue [pages/features/color-extraction.vue]
<script setup lang="ts">
useSchemaOrg([defineBreadcrumb({
  itemListElement: [
    { name: 'Home', item: '/' },
    { name: 'Features', item: '/features' },
    { name: 'Color Extraction' },
  ]
})])
</script>

<template>
  <nav aria-label="Breadcrumb" class="text-sm text-muted mb-6">
    <ol class="flex gap-2">
      <li>
        <NuxtLink to="/">
          Home
        </NuxtLink>
      </li>
      <li>/</li>
      <li>
        <NuxtLink to="/features">
          Features
        </NuxtLink>
      </li>
      <li>/</li>
      <li class="text-dimmed">
        Color Extraction
      </li>
    </ol>
  </nav>
</template>
```

The template renders visible links. Check the schema module’s emitted JSON-LD against the [breadcrumb requirements](https://developers.google.com/search/docs/appearance/structured-data/breadcrumb).

## Contextual Links in Content

Place related links where they help readers. Google’s crawlable-link guidance recommends descriptive anchor text and relevant surrounding context; it does not establish a universal body-versus-sidebar weight.

### Related Articles Component

Build a reusable component that renders related links from frontmatter data:

```vue [components/RelatedArticles.vue]
<script setup lang="ts">
const { relatedPages = [] } = defineProps<{
  relatedPages?: Array<{ path: string, title: string }>
}>()
</script>

<template>
  <aside v-if="relatedPages.length" class="mt-12 p-6 bg-muted rounded-lg">
    <h2 class="text-lg font-semibold mb-4">
      Related Articles
    </h2>
    <ul class="space-y-2">
      <li v-for="page in relatedPages" :key="page.path">
        <NuxtLink :to="page.path" class="text-primary hover:underline">
          {{ page.title }}
        </NuxtLink>
      </li>
    </ul>
  </aside>
</template>
```

This initial-load excerpt requires a configured `content` collection with title, description, and a `relatedPages` array of path/title objects. It also requires the RelatedArticles component above. Collection failures propagate; missing documents return 404:

```vue [pages/blog/[slug\\].vue]
<script setup lang="ts">
const route = useRoute()

const { data: post, error } = await useAsyncData(`post-${route.params.slug}`, () =>
  queryCollection('content')
    .where('path', '=', `/blog/${route.params.slug}`)
    .first())
if (error.value)
  throw error.value
if (!post.value)
  throw createError({ statusCode: 404, statusMessage: 'Post not found' })

useSeoMeta({
  title: post.value?.title,
  description: post.value?.description
})
</script>

<template>
  <article>
    <ContentRenderer :value="post" />
    <RelatedArticles :related-pages="post?.relatedPages || []" />
  </article>
</template>
```

### Markdown Content Links

When writing content in `.md` files with `@nuxt/content`, standard markdown links create internal connections:

```md [content/blog/nuxt-seo-guide.md]
## Setting Up Meta Tags

The foundation of any SEO strategy starts with proper meta tags.
See [configuring page titles](/learn-seo/nuxt/mastering-meta/titles) for
the complete guide.

If you're using dynamic routes, you'll also want to read about
[canonical URLs](/learn-seo/nuxt/controlling-crawlers/canonical-urls)
to prevent duplicate content.

## Sitemaps

Once your pages have proper meta tags, make sure Google can discover
them all through your [sitemap](/learn-seo/nuxt/controlling-crawlers/sitemaps).
```

Inspect the rendered Markdown links for standard anchors with usable href values. These provide navigation and crawl paths.

## Navigation and Footer Links

### Site Navigation

Site navigation exposes common destinations across pages. Choose useful links with descriptive labels.

```vue [layouts/default.vue]
<script setup lang="ts">
const navLinks = [
  { to: '/features', label: 'Features' },
  { to: '/pricing', label: 'Pricing' },
  { to: '/blog', label: 'Blog' },
  { to: '/docs', label: 'Documentation' },
]
</script>

<template>
  <div class="min-h-screen flex flex-col">
    <header class="border-b border-muted">
      <nav class="max-w-7xl mx-auto px-4 py-4 flex items-center justify-between">
        <NuxtLink to="/" class="text-xl font-bold">
          MySite
        </NuxtLink>
        <div class="flex gap-6">
          <NuxtLink
            v-for="link in navLinks"
            :key="link.to"
            :to="link.to"
            class="text-muted hover:text-default transition-colors"
          >
            {{ link.label }}
          </NuxtLink>
        </div>
      </nav>
    </header>

    <main class="flex-1 max-w-7xl mx-auto px-4 py-8">
      <slot />
    </main>
  </div>
</template>
```

Keep the main navigation focused on useful destinations. Google does not document a universal five-to-seven-link rule.

### Navigation vs Footer Weight

Choose main navigation links for frequent tasks. Use the footer for useful supporting destinations. Do not infer current ranking weights from a patent.

## Internal Links and AI Search

Crawler capabilities vary by provider. Standard anchors in the initial HTML make navigation available to clients that do not render JavaScript. Provider controls distinguish search crawling, training, and user-triggered fetches; see [crawler controls](https://nuxtseo.com/learn-seo/nuxt/controlling-crawlers).

What this means in practice: link related content together with descriptive anchor text. If you have a guide on meta tags, a guide on sitemaps, and a guide on canonical URLs, they should all link to each other. The anchor text should describe what the destination covers, not just repeat the page name.

## Auditing Your Link Graph

### Finding Broken Links with nuxt-link-checker

Use the [current Link Checker guide](https://nuxtseo.com/docs/link-checker/getting-started/introduction) for supported inspection modes and configuration. Check which routes were inspected; a build alone does not prove every dynamic destination was checked.

::module-card{slug="link-checker" .w-1/2}
::

### Checking Crawl Depth in Search Console

Use the Page indexing report and URL Inspection to inspect affected URLs. “Discovered, currently not indexed” does not identify link depth as the cause. Compare your actual link graph and Google’s reported state before diagnosing a problem.

### Identifying Orphan Pages

An orphan page has no internal incoming links. Compare the published URL inventory with links from a rendered crawl. File names alone cannot enumerate dynamic routes or prove that a page is orphaned.

For a thorough audit, crawl your site with [Screaming Frog](https://www.screamingfrog.co.uk/seo-spider/) and compare its incoming-link data with your URL inventory. Confirm the crawl includes dynamically generated pages.

## Common Mistakes

### Orphan Pages

Creating pages without incoming internal links can hinder discovery and navigation. Programmatic routes can become orphaned if no navigation links point to them.

::code-group
```vue [✅ Correct]
<script setup lang="ts">
// Hub page that links to all generated pages
const { data: products } = await useAsyncData('products', () =>
  queryCollection('content')
    .where('path', 'LIKE', '/products/%')
    .all())
</script>

<template>
  <div>
    <h1>All Products</h1>
    <!-- Every product page is reachable -->
    <NuxtLink
      v-for="product in products"
      :key="product.path"
      :to="product.path"
    >
      {{ product.title }}
    </NuxtLink>
  </div>
</template>
```

```vue [❌ Wrong]
<!-- No hub page exists -->
<!-- Product pages only reachable via sitemap.xml -->
<!-- pages/products/[slug].vue exists but nothing links to it -->
<template>
  <div>
    <h1>{{ product.title }}</h1>
    <!-- No link back to parent, no links to siblings -->
  </div>
</template>
```
::

### JavaScript Navigation Without Links

Using `@click` handlers with `navigateTo()`{lang="ts"} instead of `<NuxtLink>`{lang="html"} creates links that Googlebot cannot follow. Googlebot parses HTML to find `<a href>`{lang="html"} tags. It does not execute arbitrary click handlers.

::code-group
```vue [✅ Correct]
<template>
  <NuxtLink to="/features/color-extraction" class="btn">
    View Color Extraction
  </NuxtLink>
</template>
```

```vue [❌ Wrong]
<template>
  <!-- Googlebot cannot follow this -->
  <button @click="navigateTo('/features/color-extraction')">
    View Color Extraction
  </button>
</template>
```
::

### Excessive nofollow on Internal Links

Use crawlable links for ordinary navigation. Google treats link qualifiers as hints. Apply nofollow, sponsored, or ugc according to the relationship, not a blanket PageRank-preservation rule. See [Google’s link qualifier guidance](https://developers.google.com/search/docs/crawling-indexing/qualify-outbound-links).

### Linking to Noindexed Pages

A noindexed destination can still serve a useful reader task, such as account access. Keep useful navigation. Decide indexing separately instead of treating every such link as wasted value.

### Broken Links After URL Changes

When you rename or move pages, existing internal links break. Broken links interrupt navigation. Update internal links and redirect moved content when a relevant replacement exists. Set up redirects in your `nuxt.config.ts` when changing URLs:

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  routeRules: {
    '/old-features/color': { redirect: { to: '/features/color-extraction', statusCode: 301 } },
    '/blog/old-slug': { redirect: { to: '/blog/new-slug', statusCode: 301 } },
  }
})
```

Better yet, use `nuxt-link-checker` to catch broken links during development before they ship.

## Checklist

::checklist{#nuxt-internal-linking}
- Useful pages are reachable through crawlable navigation; verify depth against reader tasks, not a universal click limit
- Hub pages link to every spoke; spokes link back to the hub and to sibling spokes
- Anchor text describes the destination instead of saying "click here"
- Crawlable navigation uses anchors with href values, through NuxtLink or ordinary HTML links; click handlers alone are not crawl paths
- Breadcrumbs render visible links plus BreadcrumbList structured data
- Compare incoming links from a rendered crawl with the published URL inventory to find orphan pages; inspect broken links separately
- Redirects are in place for every renamed or moved URL
::

## Sitemap

See the full [sitemap](https://nuxtseo.com/sitemap.md) for all pages.
