---
url: /guide.md
---
# Getting Started

## Overview

`vite-plugin-vue-layouts-next` gives Vue Router 5 file-based routes a layout system. Layouts live in `src/layouts` and
are ordinary Vue components with a `<router-view>` in the template; every page is wrapped in one.

It consists of two parts:

* A Vite plugin that scans your layouts directory and generates the `virtual:generated-layouts` module.
* A `setupLayouts` helper that rewrites your route records so each page becomes a child of its layout.

Pages that do not choose a layout use `default.vue`. Pages that do choose one name it through `meta.layout`, using a
[normalized layout name](/config/layout-names).

You can learn more about the rationale behind the fork in the [Why](/guide/why) section, and about the route
transformation in [How it works](/guide/how-it-works).

## Installation

::: code-group

```bash [npm]
npm install -D vite-plugin-vue-layouts-next
```

```bash [yarn]
yarn add -D vite-plugin-vue-layouts-next
```

```bash [pnpm]
pnpm add -D vite-plugin-vue-layouts-next
```

:::

### Compatibility Note

This package targets Vite 6 to 8, Vue 3.2+, and Vue Router 4.0.11 or 5. Page discovery is owned by Vue Router 5's own
Vite plugin - this plugin only resolves layouts, so no page-routing plugin is needed alongside it.

### Support Policy

Which versions of the peer dependencies a release of this plugin supports follows one rule set, so it does not have to
be decided again for each release:

* **Vite** - the current major and the two previous majors, mirroring Vite's own
  [release policy](https://vite.dev/releases). Today: Vite 6, 7 and 8.
* **Vue Router** - the current major and the previous major; for each, only its latest minor is a support target.
  Today: Vue Router 5.x and 4.6.x. Older 4.x minors still install (the peer range starts at 4.0.11) but are not
  tested against.
* **Vue** - no separate floor. Vue has no LTS or backport policy, so the supported Vue range is whatever the oldest
  supported Vue Router minor requires (Vue Router 4.6 requires Vue 3.5). The peer range currently still allows
  Vue 3.2+; features that need a newer Vue degrade gracefully there and say so in their docs
  (see [Dynamic Layouts](/guide/dynamic-layout)).
* Narrowing any peer range is a breaking change and only happens in a **major** release, listed under "Removed" in
  the changelog. The next major is expected to move the floors to Vue Router 4.6 and Vue 3.5.

## Adding the Plugin

Add it to your `vite.config.ts`, after `VueRouter()`:

```js [vite.config.js]
import Vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vite'
import Layouts from 'vite-plugin-vue-layouts-next'
import VueRouter from 'vue-router/vite'

export default defineConfig({
  plugins: [VueRouter(), Vue(), Layouts()],
})
```

In `main.ts`, import Vue Router 5's generated file-based routes and wrap them with `setupLayouts`:

```js [src/main.ts]
import { setupLayouts } from 'virtual:generated-layouts'
import { createRouter } from 'vue-router'
import { routes } from 'vue-router/auto-routes'

const router = createRouter({
  // ...
  routes: setupLayouts(routes),
})
```

See the [Config Section](/config/) for the options `Layouts()` accepts.

## Writing a Layout

A layout is a standard Vue component whose template renders a `<router-view>`:

```vue [src/layouts/default.vue]
<template>
  <div class="app">
    <header>My site</header>
    <router-view />
  </div>
</template>
```

Every page without an explicit layout renders inside this one.

## Choosing a Layout Per Page

A page selects its layout through `meta.layout`, either in a `<route>` block:

```vue [src/pages/users.vue]
<route lang="yaml">
meta:
  layout: users
</route>
```

or with `definePage`:

```vue [src/pages/users.vue]
<script setup lang="ts">
definePage({
  meta: {
    layout: 'users',
  },
})
</script>
```

Both look for `src/layouts/users.vue`. Note that the value is a *layout name*, not a path - see
[Layout Names](/config/layout-names).

## Passing Props to a Layout

`meta.layout` also accepts an object with the layout `name` and the `props` to pass to the layout component:

```vue [src/pages/dashboard.vue]
<script setup lang="ts">
definePage({
  meta: {
    layout: {
      name: 'panel',
      props: {
        sidebar: true,
        title: 'Dashboard',
      },
    },
  },
})
</script>
```

The layout receives them through `defineProps`:

```vue [src/layouts/panel.vue]
<script setup lang="ts">
defineProps<{
  sidebar?: boolean
  title?: string
}>()
</script>

<template>
  <div class="panel">
    <h1>{{ title }}</h1>
    <aside v-if="sidebar">
      ...
    </aside>
    <router-view />
  </div>
</template>
```

* Omit `name` to pass props to `defaultLayout`; `name: false` renders the page without a layout, like `layout: false`.
* Props a layout does not declare fall through as attributes on its root element.
* A flat `meta.layoutProps` next to a string `layout` works too (`layout.props` wins when both are set).
* `definePage` and `<route>` blocks are extracted statically, so props must be plain serializable values. To compute
  them at runtime, use a router guard or `setPageLayout` - see [Dynamic Layouts](/guide/dynamic-layout#layout-props).

## Client Types

To get type definitions for `virtual:generated-layouts`, add the client types to your `tsconfig`:

```json [tsconfig.json]
{
  "compilerOptions": {
    "types": ["vite-plugin-vue-layouts-next/client"]
  }
}
```

## Trying It Out

The repository ships four runnable setups covering SPA, SSG, client-side layouts and nested routes. See
[Examples](/guide/examples).
