Vue.js Upgrade Guide

Compare Vue.js versions and see exactly what changes, what requires action, and what you can start using.

12Changes
1Breaking
1Actions
5Features
0Migration tools

Breaking Changes

defineComponent() function overload type changed

Action required
breakinglow impact

Vue 3.3 repurposes the rarely used defineComponent() function overload to support improved generic component typing, changing its TypeScript type behavior.

Migration

Review code that passes a function directly to defineComponent(). This overload was rarely used, but its type signature changed in Vue 3.3.

Official sources

New Features

defineOptions() introduced

featuremedium impact

Vue 3.3 introduces defineOptions(), allowing additional component options such as inheritAttrs to be declared directly inside <script setup>.

Beforevue
<script>
export default {
  inheritAttrs: false
}
</script>

<script setup>
// component logic
</script>
Aftervue
<script setup>
defineOptions({
  inheritAttrs: false
})
</script>
Migration

No migration is required. Components that previously needed a second normal <script> block solely for supported component options can use defineOptions().

Reactive Props Destructure introduced experimentally

featuremedium impact Experimental

Vue 3.3 introduces experimental support for destructuring defineProps() while preserving reactivity and allowing native default-value syntax.

Migration

No migration is required. This feature was experimental in Vue 3.3 and should be treated according to the behavior and stability of the target Vue version.

defineModel() introduced experimentally

featuremedium impact Experimental

Vue 3.3 introduces the experimental defineModel() compiler macro for declaring a component v-model prop and its corresponding update event with less boilerplate.

Beforevue
<script setup>
const props = defineProps({
  modelValue: String
})

const emit = defineEmits([
  "update:modelValue"
])
</script>
Aftervue
<script setup>
const modelValue =
  defineModel<string>()
</script>
Migration

No migration is required. In Vue 3.3 defineModel() was experimental, so adoption should account for the stability of the target Vue release.

toRef() normalization improved and toValue() introduced

featuremedium impact

Vue 3.3 enhances toRef() so it can normalize values, getters and existing refs, and introduces toValue() for normalizing values, refs and getters into values.

Aftervue
import {
  ref,
  toRef,
  toValue
} from "vue"

const existing = ref(1)

toRef(1)
toRef(() => props.count)
toRef(existing)

toValue(1)
toValue(existing)
toValue(() => props.count)
Migration

No migration is required. Composables can use toValue() when accepting values, refs or getters, and the normalization form of toRef() when a ref representation is needed.

Reactivity APIs gained better getter support

featuremedium impact

Vue 3.3 improves getter handling in reactivity utilities, making getter-based reactive inputs easier and more efficient to consume in composables.

Beforevue
useFeature(
  computed(() => props.id)
)
Aftervue
useFeature(
  () => props.id
)
Migration

No migration is required. Composables can increasingly accept getters directly instead of requiring callers to allocate intermediate computed refs.

TypeScript

SFC macros support imported and complex TypeScript types

typescripthigh impact

Vue 3.3 expands type support in macros such as defineProps() and defineEmits(), allowing imported types and a broader set of complex TypeScript types to be used directly.

Beforevue
<script setup lang="ts">
interface Props {
  name: string
  age?: number
}

defineProps<Props>()
</script>
Aftervue
<script setup lang="ts">
import type { UserProps } from "./types"

defineProps<UserProps>()
</script>
Migration

No migration is required. Existing local type declarations remain valid. Imported and supported complex types can now be used directly with SFC compiler macros.

Generic components supported in <script setup>

typescripthigh impact

Vue 3.3 adds native support for declaring generic Single-File Components using the generic attribute on <script setup>.

Aftervue
<script
  setup
  lang="ts"
  generic="T extends string | number"
>
defineProps<{
  items: T[]
  selected: T
}>()
</script>
Migration

No migration is required. Generic components can now express relationships between prop types directly in <script setup>.

defineEmits gained a more ergonomic TypeScript syntax

typescriptmedium impact

Vue 3.3 allows type-based defineEmits declarations to use event names as object keys and tuple types for event arguments.

Beforevue
const emit = defineEmits<{
  (e: "change", id: number): void
  (e: "update", value: string): void
}>()
Aftervue
const emit = defineEmits<{
  change: [id: number]
  update: [value: string]
}>()
Migration

No migration is required. The previous call-signature syntax remains supported. The tuple syntax can be adopted for more concise event typing.

Typed slots with defineSlots()

typescripthigh impact

Vue 3.3 introduces the defineSlots() compiler macro for providing IDE and vue-tsc type information about slot names and slot props.

Aftervue
<script setup lang="ts">
defineSlots<{
  default?: (
    props: { message: string }
  ) => any

  item?: (
    props: { id: number }
  ) => any
}>()
</script>
Migration

No migration is required. defineSlots() can be adopted when slot names and slot props should be type checked.

JSX import source support added

typescriptmedium impact

Vue 3.3 adds support for TypeScript's jsxImportSource option, allowing Vue JSX typing to be opted into explicitly and reducing conflicts with other JSX ecosystems.

Aftervue
{
  "compilerOptions": {
    "jsx": "preserve",
    "jsxImportSource": "vue"
  }
}
Migration

Vue 3.3 still provides the global JSX namespace for backwards compatibility, but TSX users should configure jsxImportSource for forward compatibility because the default global registration was planned for removal in Vue 3.4.

defineComponent() gained generic component support

typescriptmedium impact

Vue 3.3 improves TypeScript support for authoring generic components with defineComponent(), complementing generic support in <script setup>.

Migration

No migration is required. Library and component authors can use the improved generic typing when component APIs need to preserve relationships between types.

Official sources