Index of every page on this site: llms.txt

Get instant feedback on broken links directly in your editor. The ESLint integration provides two rules that validate relative URLs against your app's known routes and sitemap data.

Rules

Checks that relative URLs match a known vue-router route pattern. This catches links to pages that don't exist at all.

Severity: error

<!-- ✅ Valid: /about exists as a page -->
<NuxtLink to="/about" />

<!-- ✅ Valid: matches /blog/:slug dynamic route -->
<NuxtLink to="/blog/my-post" />

<!-- ❌ Error: no route matches /abot -->
<NuxtLink to="/abot" />

Checks that relative URLs exist in the sitemap. For dynamic routes, it warns when sibling URLs exist in the sitemap but the linked URL does not.

Severity: warn

<!-- ✅ Valid: /blog/hello-world is in the sitemap -->
<NuxtLink to="/blog/hello-world" />

<!-- ⚠️ Warning: /blog/typo matches /blog/:slug but isn't in sitemap -->
<!-- (while other /blog/* URLs are) -->
<NuxtLink to="/blog/typo" />

What Gets Checked

Both rules scan for relative URLs in:

  • Vue templates: <NuxtLink to="...">, <RouterLink to="...">, <a href="...">
  • TypeScript/JavaScript: navigateTo('...'), router.push('...'), router.replace('...')
  • Markdown: [text](/url) link syntax (via processor)

External URLs, anchors, mailto/tel links, and dynamic bindings are automatically skipped.

You can exclude a link from checking in several ways:

Add rel="nofollow" to any link element to skip both rules. This is semantic HTML that signals the link shouldn't be followed by crawlers.

<a href="/external-redirect" rel="nofollow">
Skip this
</a>

<NuxtLink to="/unindexed-page" rel="nofollow">
Also skipped
</NuxtLink>

Links to static files (served from public/) are automatically skipped. This includes .pdf, .png, .jpg, .jpeg, .gif, .webp, .avif, .svg, .ico, .xml, .txt, .json, .js, .css, .woff, .woff2, and other common asset file extensions.

<!-- All skipped automatically -->
<a href="/document.pdf">
Download
</a>

<a href="/favicon.ico">
Icon
</a>

ESLint inline disable: Use standard ESLint disable comments (eslint-disable-next-line) to skip individual lines in Vue templates or scripts.

Setup

If you're using @nuxt/eslint, Nuxt Link Checker automatically registers both rules. Zero-config.

For projects not using @nuxt/eslint, import the plugin in your ESLint flat config:

import linkCheckerPlugin from 'nuxt-link-checker/eslint'

export default [
  {
    files: ['**/*.vue', '**/*.ts'],
    plugins: {
      'link-checker': linkCheckerPlugin,
    },
    rules: {
      'link-checker/valid-route': 'error',
      'link-checker/valid-sitemap-link': 'warn',
    },
  },
  // For markdown files
  {
    files: ['**/*.md'],
    plugins: {
      'link-checker': linkCheckerPlugin,
    },
    processor: 'link-checker/markdown',
    rules: {
      'link-checker/valid-route': 'error',
      'link-checker/valid-sitemap-link': 'warn',
    },
  },
]

How Route Data Gets Generated

The rules read route data from .nuxt/link-checker/routes.json, which nuxt dev or nuxt prepare generates. Make sure to run one of these before linting.

If the file is missing, the rules check no links and ESLint prints a warning with the expected path.

Nuxt Link Checker collects route data in two phases:

  1. On pages:resolved: Nuxt Link Checker writes static page routes and dynamic route patterns (e.g., /blog/:slug) immediately.
  2. After dev server starts: If you install @nuxtjs/sitemap, Nuxt Link Checker merges resolved sitemap URLs, capturing dynamic content from @nuxt/content, i18n, and custom sources.

valid-sitemap-link needs the sitemap URLs from phase 2. Until the dev server has merged them, it checks no links, since valid-route already reports unknown routes.

The route file is automatically refreshed when files change during development.

Configuration

Both rules accept an options object:

{
  "link-checker/valid-route": ["error", {
    "routesFile": "/path/to/routes.json",
    "rootDir": "/path/to/project"
  }]
}
Was this page helpful?