> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/vuejs/vitepress/llms.txt
> Use this file to discover all available pages before exploring further.

# Routing

> Understanding VitePress file-based routing, clean URLs, and dynamic routes

# Routing

VitePress uses **file-based routing**, which means your Markdown files automatically become pages based on their location in your project. No routing configuration needed!

## File-Based Routing Basics

Every `.md` file in your source directory becomes an HTML page with the same path structure.

### Simple Example

Given this file structure:

```
.
├─ guide
│  ├─ getting-started.md
│  └─ index.md
├─ index.md
└─ prologue.md
```

VitePress generates these URLs:

```
index.md                  →  /index.html (accessible as /)
prologue.md               →  /prologue.html
guide/index.md            →  /guide/index.html (accessible as /guide/)
guide/getting-started.md  →  /quickstart.html
```

<Tip>
  The resulting HTML can be hosted on any web server that serves static files.
</Tip>

## Project Root vs Source Directory

Understanding these concepts is key to organizing your VitePress project.

### Project Root

The **project root** is where VitePress looks for the `.vitepress` directory:

```
.
├─ docs                    # ← project root
│  ├─ .vitepress           # config directory
│  ├─ getting-started.md
│  └─ index.md
└─ package.json
```

Run VitePress commands from your project directory:

```bash theme={null}
vitepress dev docs
```

This produces:

```
docs/index.md            →  /index.html (accessible as /)
docs/getting-started.md  →  /getting-started.html
```

### Source Directory

The **source directory** is where your Markdown files live. By default, it's the same as the project root, but you can customize it:

```javascript .vitepress/config.js theme={null}
export default {
  srcDir: 'src'
}
```

With this configuration:

```
.                          # project root
├─ .vitepress              # config dir
└─ src                     # ← source dir
   ├─ getting-started.md
   └─ index.md
```

Your routes become:

```
src/index.md            →  /index.html
src/getting-started.md  →  /getting-started.html
```

<Note>
  The `srcDir` option is useful for keeping your documentation separate from configuration files.
</Note>

## Linking Between Pages

Use both absolute and relative paths in your Markdown links.

### Best Practices

<Tabs>
  <Tab title="Recommended">
    **Omit file extensions** so VitePress can generate correct URLs based on your config:

    ```markdown theme={null}
    [Getting Started](./getting-started)
    [Getting Started](../quickstart)
    ```
  </Tab>

  <Tab title="Avoid">
    Don't include `.md` or `.html` extensions:

    ```markdown theme={null}
    [Getting Started](./getting-started.md)  ❌
    [Getting Started](./getting-started.html)  ❌
    ```
  </Tab>
</Tabs>

### Linking to Non-VitePress Pages

For pages not generated by VitePress, specify the target explicitly:

```markdown theme={null}
[Link to pure.html](/pure.html){target="_self"}
```

Or use HTML anchor tags:

```html theme={null}
<a href="/pure.html" target="_self">Link to pure.html</a>
```

## Clean URLs

Remove `.html` extensions from your URLs for cleaner, more professional links.

<Warning>
  Clean URLs require server-side support. Not all hosting platforms support this feature.
</Warning>

### How It Works

By default: `example.com/path.html`\
With clean URLs: `example.com/path`

### Enable Clean URLs

<Steps>
  <Step title="Check server support">
    These platforms support clean URLs automatically:

    * **Netlify** ✓
    * **GitHub Pages** ✓
    * **Vercel** (requires [`cleanUrls` in `vercel.json`](https://vercel.com/docs/concepts/projects/project-configuration#cleanurls))
  </Step>

  <Step title="Enable in VitePress config">
    Add to `.vitepress/config.js`:

    ```javascript .vitepress/config.js theme={null}
    export default {
      cleanUrls: true
    }
    ```
  </Step>
</Steps>

With clean URLs enabled:

* Internal links are generated without `.html` extensions
* Client-side redirects from `.html` to clean URLs
* Better SEO and user experience

### Manual Clean URLs

If your server doesn't support clean URLs, use this directory structure:

```
.
├─ getting-started
│  └─ index.md        →  /getting-started/
├─ installation
│  └─ index.md        →  /installation/
└─ index.md           →  /
```

## Route Rewrites

Customize the mapping between source files and generated URLs - perfect for monorepos and complex structures.

### Use Case: Monorepo Documentation

You have packages with documentation alongside source code:

```
.
└─ packages
   ├─ pkg-a
   │  └─ src
   │     ├─ foo.md
   │     └─ index.md
   └─ pkg-b
      └─ src
         ├─ bar.md
         └─ index.md
```

You want these URLs:

```
packages/pkg-a/src/index.md  →  /pkg-a/index.html
packages/pkg-a/src/foo.md    →  /pkg-a/foo.html
packages/pkg-b/src/index.md  →  /pkg-b/index.html
packages/pkg-b/src/bar.md    →  /pkg-b/bar.html
```

### Static Rewrites

Define explicit mappings:

```typescript .vitepress/config.js theme={null}
export default {
  rewrites: {
    'packages/pkg-a/src/index.md': 'pkg-a/index.md',
    'packages/pkg-a/src/foo.md': 'pkg-a/foo.md',
    'packages/pkg-b/src/index.md': 'pkg-b/index.md',
    'packages/pkg-b/src/bar.md': 'pkg-b/bar.md'
  }
}
```

### Dynamic Rewrites with Parameters

Use route parameters to avoid repetition:

```typescript .vitepress/config.js theme={null}
export default {
  rewrites: {
    'packages/:pkg/src/:slug*': ':pkg/:slug*'
  }
}
```

<Note>
  Rewrite patterns use the [`path-to-regexp`](https://github.com/pillarjs/path-to-regexp/tree/6.x#parameters) package syntax.
</Note>

### Function-Based Rewrites

Use a function for complex rewrite logic:

```typescript .vitepress/config.js theme={null}
export default {
  rewrites(id) {
    return id.replace(/^packages\/([^/]+)\/src\//, '$1/')
  }
}
```

<Warning>
  **Important:** When using rewrites, relative links should be based on the **rewritten paths**, not the original file structure.
</Warning>

## Dynamic Routes

Generate multiple pages from a single template using dynamic data - perfect for API documentation, blog posts, or product catalogs.

### The Basics

Create a route template with parameters in square brackets:

```
.
└─ packages
   ├─ [pkg].md         # route template
   └─ [pkg].paths.js   # route paths loader
```

The `[pkg]` parameter will be replaced with actual values from your paths loader.

### Paths Loader File

Create a `.paths.js` file that exports a `paths` function:

```javascript packages/[pkg].paths.js theme={null}
export default {
  paths() {
    return [
      { params: { pkg: 'foo' }},
      { params: { pkg: 'bar' }}
    ]
  }
}
```

This generates:

```
.
└─ packages
   ├─ foo.html
   └─ bar.html
```

### TypeScript Support

Use `defineRoutes` for type safety:

```typescript packages/[pkg].paths.ts theme={null}
import { defineRoutes } from 'vitepress'

export default defineRoutes({
  async paths() {
    return [
      { params: { pkg: 'foo' } },
      { params: { pkg: 'bar' } }
    ]
  },
  
  async transformPageData(pageData) {
    pageData.title = `${pageData.title} · Packages`
  }
})
```

<Tip>
  The `defineRoutes` helper provides TypeScript intellisense for route configuration.
</Tip>

### Multiple Parameters

Use multiple parameters in your route:

<CodeGroup>
  ```text File Structure theme={null}
  .
  └─ packages
     ├─ [pkg]-[version].md
     └─ [pkg]-[version].paths.js
  ```

  ```javascript Paths Loader theme={null}
  export default {
    paths() {
      return [
        { params: { pkg: 'foo', version: '1.0.0' }},
        { params: { pkg: 'foo', version: '2.0.0' }},
        { params: { pkg: 'bar', version: '1.0.0' }},
        { params: { pkg: 'bar', version: '2.0.0' }}
      ]
    }
  }
  ```

  ```text Output theme={null}
  .
  └─ packages
     ├─ foo-1.0.0.html
     ├─ foo-2.0.0.html
     ├─ bar-1.0.0.html
     └─ bar-2.0.0.html
  ```
</CodeGroup>

### Generating Paths from Data

Load data from local files or remote APIs:

<Tabs>
  <Tab title="Local Files">
    ```javascript theme={null}
    import fs from 'fs'

    export default {
      paths() {
        return fs
          .readdirSync('packages')
          .map((pkg) => {
            return { params: { pkg }}
          })
      }
    }
    ```
  </Tab>

  <Tab title="Remote API">
    ```javascript theme={null}
    export default {
      async paths() {
        const pkgs = await (
          await fetch('https://my-api.com/packages')
        ).json()
        
        return pkgs.map((pkg) => {
          return {
            params: {
              pkg: pkg.name,
              version: pkg.version
            }
          }
        })
      }
    }
    ```
  </Tab>
</Tabs>

### Watching Data Files

Automatically rebuild pages when data or templates change:

```javascript posts/[slug].paths.js theme={null}
import fs from 'node:fs'

export default {
  // Watch for changes during development
  watch: [
    './templates/**/*.njk',     // Template files
    '../data/**/*.json'         // Data files
  ],
  
  paths(watchedFiles) {
    // watchedFiles contains absolute paths of matched files
    const dataFiles = watchedFiles.filter(file => file.endsWith('.json'))
    
    return dataFiles.map(file => {
      const data = JSON.parse(fs.readFileSync(file, 'utf-8'))
      
      return {
        params: { slug: data.slug },
        content: data.content  // Inject content
      }
    })
  }
}
```

<Note>
  The `watch` option accepts [glob patterns](https://github.com/mrmlnc/fast-glob#pattern-syntax) relative to the `.paths.js` file.
</Note>

### Accessing Parameters in Pages

Use parameters in your Markdown template:

```markdown packages/[pkg].md theme={null}
# Package: {{ $params.pkg }}

Version: {{ $params.version }}
```

Or in Vue components:

```vue theme={null}
<script setup>
import { useData } from 'vitepress'

const { params } = useData()

console.log(params.value.pkg)
</script>

<template>
  <h1>{{ params.pkg }}</h1>
</template>
```

### Rendering Raw Content

Inject content from external sources without passing it as parameters:

```javascript theme={null}
export default {
  async paths() {
    const posts = await (
      await fetch('https://my-cms.com/blog-posts')
    ).json()
    
    return posts.map((post) => {
      return {
        params: { id: post.id },
        content: post.content  // Raw Markdown or HTML
      }
    })
  }
}
```

In your template, use the special `@content` marker:

```markdown theme={null}
---
title: Blog Post
---

<!-- @content -->
```

<Warning>
  Avoid passing large content in `params` as it's serialized in the client JavaScript bundle. Use the `content` property instead.
</Warning>

## Setting a Base Path

If your site is deployed to a subdirectory, configure the base path:

```javascript .vitepress/config.js theme={null}
export default {
  base: '/repo/'  // For https://username.github.io/repo/
}
```

<Tip>
  **GitHub/GitLab Pages**: Set `base` to `'/repo/'` if deploying to `user.github.io/repo/`
</Tip>

## Next Steps

<CardGroup cols={2}>
  <Card title="Deploy Your Site" icon="upload" href="./deploying">
    Learn how to build and deploy your VitePress site
  </Card>

  <Card title="Markdown Features" icon="markdown" href="/markdown">
    Explore VitePress's powerful Markdown extensions
  </Card>

  <Card title="Asset Handling" icon="image" href="/assets">
    Learn how to work with images and static files
  </Card>

  <Card title="Data Loading" icon="database" href="/data-loading">
    Load data from local or remote sources
  </Card>
</CardGroup>
