oxc-project/oxc · warning · OxcDiagnostic

`model` definition is deprecated.

Error message

`model` definition is deprecated.

What it means

Diagnostic from oxlint's vue/no-deprecated-model-definition rule (since oxlint 1.63.0). It fires on the Vue 2 `model` option used to customize v-model (e.g. model: { prop: 'checked', event: 'change' }). Vue 3 replaced it with the standard modelValue prop and update:modelValue event, and ignores the old option — the binding silently stops working. The rule's allowVue3Compat option (allow_vue3_compat) permits the exact forwards-compatible shape and routes anything else to this base diagnostic.

Source

Thrown at crates/oxc_linter/src/rules/vue/no_deprecated_model_definition.rs:21

use serde::{Deserialize, Serialize};

use oxc_ast::{
    AstKind,
    ast::{Expression, ObjectExpression, ObjectPropertyKind},
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;

use crate::{
    AstNode,
    context::LintContext,
    rule::{DefaultRuleConfig, Rule},
    utils::is_vue_component_options_object,
};

fn deprecated_model_diagnostic(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("`model` definition is deprecated.").with_label(span)
}

fn vue3_compat_diagnostic(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn(
        "`model` definition is deprecated. You may use the Vue 3-compatible `modelValue`/`update:modelValue` though.",
    )
    .with_label(span)
}

#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase", default, deny_unknown_fields)]
struct NoDeprecatedModelDefinitionConfig {
    /// Allow `model: { prop: 'modelValue', event: 'update:modelValue' }` (or
    /// the kebab-case `model-value` variant) which is forwards-compatible with
    /// Vue 3's `v-model`.
    allow_vue3_compat: bool,
}

View on GitHub (pinned to e1e7af627c)

Solutions

  1. Rename the prop to modelValue and emit update:modelValue: this.$emit('update:modelValue', val)
  2. If the component already targets the compat shape, verify prop: 'modelValue', event: 'update:modelValue' exactly and set allowVue3Compat: true
  3. For named v-models (v-model:title), use the update:title event convention

Example fix

// before
model: {
  prop: 'checked',
  event: 'change',
},
props: ['checked'],
// after
props: ['modelValue'],
emits: ['update:modelValue'],
methods: {
  onInput(e) { this.$emit('update:modelValue', e.target.value) },
}
Defensive patterns

Strategy: validation

Validate before calling

# find custom v-model options
grep -rnE "^\s*model: *\{" --include='*.vue' src

Prevention

When it happens

Trigger: A Vue component options object (is_vue_component_options_object) declares a `model` property, and either allowVue3Compat is false or the option's prop/event pair is not exactly modelValue/update:modelValue (or the kebab model-value variant).

Common situations: Form/input wrapper components migrated from Vue 2 that customized v-model's prop name; after upgrade the component accepts `checked` in code but templates using v-model bind to modelValue, causing undefined values with no error.

Related errors


AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20). Data as JSON: /api/errors/d493f09f17bcdcbf. Report an issue: GitHub.