Migration to v4

A comprehensive guide to migrate your application from Nuxt UI v3 to Nuxt UI v4.

Nuxt UI v4 marks a major milestone: Nuxt UI and Nuxt UI Pro are now unified into a single, fully open-source and free library. You now have access to 100+ production-ready components, all available in the @nuxt/ui package.

Nuxt UI v4 requires Nuxt 4 due to some dependencies. Make sure to upgrade to Nuxt 4 before migrating to Nuxt UI v4.

This guide provides step-by-step instructions to migrate your application from v3 to v4.

Migrate your project

From Nuxt UI Pro

  1. Replace @nuxt/ui-pro with @nuxt/ui in your package.json:
pnpm remove @nuxt/ui-pro
pnpm add @nuxt/ui@alpha
  1. Replace @nuxt/ui-pro with @nuxt/ui in your nuxt.config.ts:
nuxt.config.ts
export default defineNuxtConfig({
  modules: [
-   '@nuxt/ui-pro',
+   '@nuxt/ui'
  ]
})
  1. Replace @nuxt/ui-pro with @nuxt/ui in your vite.config.ts:
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
- import uiPro from '@nuxt/ui-pro/vite'
+ import ui from '@nuxt/ui/vite'

export default defineConfig({
  plugins: [
    vue(),
-   uiPro({
+   ui({
      ui: {
        colors: {
          primary: 'green',
          neutral: 'slate'
        }
      }
    })
  ]
})
  1. Use the ui key instead of uiPro in your app.config.ts:
app.config.ts
export default defineAppConfig({
  ui: {
    colors: {
      primary: 'green',
      neutral: 'slate'
    },
+   pageCard: {
+     slots: {
+       root: 'rounded-xl',
+     }
+   }
  },
- uiPro: {
-   pageCard: {
-     slots: {
-       root: 'rounded-xl',
-     }
-   }
- }
})
  1. Use the ui key instead of uiPro in your vite.config.ts:
vite.config.ts
export default defineConfig({
  plugins: [
    vue(),
    ui({
      ui: {
        colors: {
          primary: 'green',
          neutral: 'slate'
        },
+       pageCard: {
+         slots: {
+           root: 'rounded-xl',
+         }
+       }
      },
-     uiPro: {
-       pageCard: {
-         slots: {
-           root: 'rounded-xl',
-         }
-       }
-     }
    })
  ]
})
  1. Replace @nuxt/ui-pro with @nuxt/ui in your CSS:
app/assets/css/main.css
@import "tailwindcss";
- @import "@nuxt/ui-pro";
+ @import "@nuxt/ui";
src/assets/css/main.css
@import "tailwindcss";
- @import "@nuxt/ui-pro";
+ @import "@nuxt/ui";

From Nuxt UI

  1. When upgrading from Nuxt UI v3, you simply need to update to v4:
pnpm add @nuxt/ui@alpha

Changes from v3

After upgrading to Nuxt UI v4, please note the following important changes:

Merged components

Nuxt UI Pro components have been integrated into the main @nuxt/ui package. You can keep using them as before, but you now need to import from @nuxt/ui instead of @nuxt/ui-pro:

- import type { BannerProps } from '@nuxt/ui-pro'
+ import type { BannerProps } from '@nuxt/ui'

Renamed components

Several components have been renamed for better consistency:

  1. ButtonGroup has been replaced with FieldGroup:
<template>
- <UButtonGroup>
+ <UFieldGroup>
    <UButton label="Button" />
    <UButton icon="i-lucide-chevron-down" />
- </UButtonGroup>
+ </UFieldGroup>
</template>
  1. PageMarquee has been replaced with Marquee:
<template>
- <UPageMarquee :items="items" />
+ <UMarquee :items="items" />
</template>

Removed components

Some components have been removed in favor of more standard alternatives:

  1. PageAccordion has been replaced with Accordion:
<template>
- <UPageAccordion :items="faqItems" />
+ <UAccordion :items="items" :unmount-on-hide="false" :ui="{ trigger: 'text-base', body: 'text-base text-muted' }" />
</template>

AI SDK v5 migration (optional)

This section only applies if you're using the AI SDK and chat components (ChatMessage, ChatMessages, ChatPrompt, ChatPromptSubmit, ChatPalette). If you're not using AI features, you can skip this section.

  1. Update @ai-sdk/vue and ai dependencies in your package.json:
{
  "dependencies": {
-   "@ai-sdk/vue": "^1.2.x",
+   "@ai-sdk/vue": "^2.0.x",
-   "ai": "^4.3.x"
+   "ai": "^5.0.x"
  }
}
  1. useChat composable has been replaced with the new Chat class:
<script setup lang="ts">
- import { useChat } from '@ai-sdk/vue'
+ import { Chat } from '@ai-sdk/vue'
+ import type { UIMessage } from 'ai'

- const { messages, input, handleSubmit, status, error, reload, setMessages } = useChat()
+ const messages: UIMessage[] = []
+ const input = ref('')
+
+ const chat = new Chat({
+   messages
+ })
+
+ function handleSubmit(e: Event) {
+   e.preventDefault()
+   chat.sendMessage({ text: input.value })
+   input.value = ''
+ }
</script>
  1. Messages now use parts instead of content:
// When manually creating messages
- setMessages([{
+ messages.push({
  id: '1',
  role: 'user',
- content: 'Hello world'
+ parts: [{ type: 'text', text: 'Hello world' }]
- }])
+ })

// In templates
<template>
- <UChatMessage :content="message.content" />
+ <UChatMessage :parts="message.parts" />
</template>
  1. Some methods have been renamed:
// Regenerate the last message
- reload()
+ chat.regenerate()

// Access chat state
- :messages="messages"
- :status="status"
+ :messages="chat.messages"
+ :status="chat.status"
  1. New getTextFromMessage utility to extract text from AI SDK v5 message parts:
<script setup lang="ts">
import { getTextFromMessage } from '@nuxt/ui/utils/ai'
</script>

<template>
  <UChatMessages :messages="chat.messages" :status="chat.status">
    <template #content="{ message }">
      <!-- Extract text from message parts and render with MDC -->
      <MDC :value="getTextFromMessage(message)" :cache-key="message.id" unwrap="p" />
    </template>
  </UChatMessages>
</template>
For more details on AI SDK v5 changes, review the official AI SDK v5 migration guide.
View all changes from AI SDK v4 to v5 in the upgrade PR for a detailed migration reference.

Updated modelModifiers for UInput and UTextarea

The modelModifiers shape used by UInput and UTextarea has changed in v4:

  • The nullify modifier was renamed to nullable (it converts empty/blank values to null).
  • A new optional modifier was added (it converts empty/blank values to undefined).

Examples:

- <UInput v-model.nullify="value" />
+ <UInput v-model.nullable="value" />
- <UTextarea v-model="value" :model-modifiers="{ nullify: true }" />
+ <UTextarea v-model="value" :model-modifiers="{ nullable: true }" />

Use nullable when you want empty values as null, and optional when you prefer undefined for absent values.