Migration
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 newqueryCollection()
fetchContentNavigation()
API is replaced with newqueryCollectionNavigation()
- 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. useContent()
composable is removedsearchContent()
is dropped in favor of the newqueryCollectionSearchSections
API- Full text search can easily be done using the
queryCollectionSearchSections
API, check this section to see how
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
<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" />
- Components created under the
components/content
directory are no longer automatically registered as global components. If you use dynamic rendering to render these components outside markdown files, you must manually register them in your Nuxt app. Check out the Nuxt - Custom Components Directories documentation for more information on how to do so.
Types
import type { NavItem } from '@nuxt/content/dist/runtime/types'
is remplaced withimport 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 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
Nuxt Studio integration
- The studio module has been deprecated and a new generic
Preview API
has been implemented directly into Nuxt Content, you can remove the@nuxthq/studio
package from your dependencies and from thenuxt.config.ts
modules. Instead we just need to enable the preview mode in the Nuxt configuration file by binding the Studio API.
export default defineNuxtConfig({
content: {
preview: {
api: 'https://api.nuxt.studio
}
},
})
- In order to keep the app config file updatable from Studio we just need to update the helper import of the
nuxt.schema.ts
file from@nuxthq/studio/theme
to@nuxt/content/preview
.
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.
<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>
queryContent
to queryCollections
Converting
As we mentioned above, queryContent
is dropped in favor of new collection based queryCollection
. There are two main differences between these two:
queryCollection
is building a query for an SQL database.queryCollection
does the search only inside the specified collection. You should know the collection's name (key on config).
// 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()
// 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()
queryContent().findSurround()
Convert
Surround now has its own separate API.
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']
}
)
ProsePre
, ProseCode
, and ProseCodeInline
components Consolidate
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.
- MDC will now map and parse single backticks
`
asProseCode
instead ofProseCodeInline
. - MDC will now map and parse block code starting with three backticks
```
asProsePre
component.
Suggested Changes:
- Your current
ProseCode
logic should be moved toProsePre
- Rename your
ProseCodeInline
components toProseCode