---
title: "Migration"
description: "How to migrate from v2 to v3"
canonical_url: "https://content.nuxt.com/docs/getting-started/migration"
---
# Migration

> How to migrate from v2 to v3

Nuxt Content v3 has been rebuilt from the ground up, resulting in a new library with enhanced capabilities. While we've redesigned concepts and components in a similar way as Content v2, breaking changes are inevitable.

Don't worry, you don't need to modify your content files. We made sure that Content v3 handles content in the same way as Content v2.

## Changes

### Vue utils

- `queryContent()` API is replaced with new `queryCollection()`

<prose-tip>

The new API is backed by SQL and content queries happens within a specific collection.

</prose-tip>

- `fetchContentNavigation()` API is replaced with new `queryCollectionNavigation()`
- Surroundings now has its own separate API `queryCollectionItemSurroundings()`
- Document driven mode is dropped: `Markdown` files will not convert to Nuxt pages automatically, you need to create pages, [check this section to see how](https://content.nuxt.com/docs/components/content-renderer#example-usage).
- `useContent()` composable is removed
- `searchContent()` is dropped in favor of the new `queryCollectionSearchSections` API
- Full text search can easily be done using the `queryCollectionSearchSections` API, [check this section to see how](https://content.nuxt.com/docs/advanced/fulltext-search)

### Components

- All content should be rendered using `<ContentRenderer>` component. `<ContentDoc>`, `<ContentList>`, `<ContentNavigation>` and `<ContentQuery>` components are dropped in v3.
- `<ContentSlot>` and `<MDCSlot>` components are not supported in v3. Instead components can simply use Vue's native `<slot>` component

<prose-note>

`<ContentSlot>` and `<MDCSlot>` was initially pro to manipulate content before rendering and removing wrapping paragraphs from slot content. This unwrapping behavior is now supported via `mdc-unwrap` attribute in `<slot>` component. Example: `<slot mdc-unwrap="p" />`

</prose-note>

- Components created under the `components/content` directory are no longer automatically registered as global components. If you use [dynamic rendering](https://vuejs.org/guide/essentials/component-basics.html#dynamic-components) to render these components outside markdown files, you must manually register them in your Nuxt app. Check out the [Nuxt - Custom Components Directories](https://nuxt.com/docs/guide/directory-structure/components#custom-directories) documentation for more information on how to do so.

### Types

- `import type { NavItem } from '@nuxt/content/dist/runtime/types'` is replaced with `import type { ContentNavigationItem } from '@nuxt/content'`

### General

- `_dir.yml` files are renamed to `.navigation.yml`
- There is no source option in module options, instead you can define [multiple sources](https://content.nuxt.com/docs/collections/sources) for your collections in `content.config.ts`.
- Document `._path` is now renamed to `.path`, likewise all internal fields with `_` prefix are removed or renamed.
- `useContentHelpers()` is removed
- Module does not ignore dot files by default, you can ignore them by adding `ignore: ['**/.*']` in `exclude` options of your collection source.
- Due to SQL limitations, sort order now uses alphabetical order instead for numerical order. Check out the [Ordering Files](https://content.nuxt.com/docs/collections/types#ordering-files) section for more information.
- Module options have changed from v2. Check out [configuration page](https://content.nuxt.com/docs/getting-started/configuration) for details.

## Implement Document Driven mode in v3

Implementing document driven mode in Content v3 is quite easy. All you need is to create a catch-all page in Nuxt and fetch contents based on route path.

```vue [pages/[...slug].vue]
<script lang="ts" setup>
const route = useRoute()
const { data: page } = await useAsyncData(route.path, () => {
  return queryCollection('content').path(route.path).first()
})
</script>

<template>
  <div>
    <header><!-- ... --></header>

    <ContentRenderer v-if="page" :value="page" />

    <footer><!-- ... --></footer>
  </div>
</template>
```

## Converting `queryContent` to `queryCollections`

As we mentioned above, `queryContent` is dropped in favor of new collection based `queryCollection`. There are two main differences between these two:

1. `queryCollection` is building a query for an SQL database.
2. `queryCollection` does the search only inside the specified collection. You should know the collection's name (key on config).

```ts [Find content with path]
// Content v2
const v2Query = await queryContent(route.path).findOne()
// Content v3 - don't forget to create `content` collection in `content.config.ts`
const v3Query = await queryCollection('content').path(route.path).first()
```

```ts [Find contents with custom filter]
// Content v2
const v2Query = await queryContent()
  .where({ path: /^\/hello\/.*/ })
  .find()
// Content v3 - don't forget to create `content` collection in `content.config.ts`
const v3Query = await queryCollection('content')
  .where('path', 'LIKE', '/hello%')
  .first()
```

<prose-note to="https://content.nuxt.com/docs/collections/define">

Check the dedicated section for more info about collections

</prose-note>

## Convert `queryContent().findSurround()`

Surround now has its own separate API.

```ts
const targetPath = '/docs'

// Content v2
const v2Surround = await queryContent(targetPath)
  .only(['title', 'description', 'navigation'])
  .findSurround(withoutTrailingSlash(route.path))

// Content v3 - don't forget to create `content` collection in `content.config.ts`
const v3Surround = await queryCollectionItemSurroundings(
  'content',
  targetPath,
  {
    fields: ['title', 'description', 'navigation']
  }
)
```

<prose-note>

Check the dedicated section for more information about the

</prose-note>

## Consolidate `ProsePre`, `ProseCode`, and `ProseCodeInline` components

Many `ProsePre` components are thin wrappers around the `ProseCode` component. We've consolidated these three components into two components. There is now no difference between `ProsePre` and multi-line code blocks.

1. MDC will now map and parse single backticks ``` as `ProseCode` instead of `ProseCodeInline`.
2. MDC will now map and parse block code starting with three backticks````` as `ProsePre` component.

**Suggested Changes:**

1. Your current `ProseCode` logic should be moved to `ProsePre`
2. Rename your `ProseCodeInline` components to `ProseCode`

## `_dir.yml` files are renamed to `.navigation.yml`

In Content v3, we renamed `_dir.yml` to `.navigation.yml`. The new name better reflects the purpose of these files.<br />


Module uses these files to gather information about directories for generating navigation.

Note that in order to make these files available for Module, you should define your collection's source in
a way that includes these files. For example `source: '**'` and `source: '**/*.{md,yml}'` will include these files
in collection, but `source: '**/*.md'` will not include them.

## Ignore dot files

By default, Content v3 does not ignore dot files. If you want to ignore them, you can add `ignore: ['**/.*']` in the `exclude` option of your collection source.

```ts
defineCollection({
  source: {
    include: '**',
    exclude: ['**/.*']
  }
})
```

Note that the above pattern will also exclude `.navigation.yml` file from collection. If you use `.navigation.yml` and want to keep them
you can use `**/.(!(navigation.yml))` pattern to exclude all dot files except `.navigation.yml`.

```ts
defineCollection({
  source: {
    include: '**',
    exclude: ['**/.!(navigation.yml)']
  }
})
```


## Sitemap

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