diff --git a/src/.vuepress/config.js b/src/.vuepress/config.js
index 2b6e141773..af6106dce0 100644
--- a/src/.vuepress/config.js
+++ b/src/.vuepress/config.js
@@ -90,6 +90,7 @@ const sidebar = {
'migration',
'migration/global-api',
'migration/treeshaking',
+ 'migration/v-model',
'migration/functional-components',
'migration/async-components',
'migration/custom-directives'
diff --git a/src/guide/migration.md b/src/guide/migration.md
index a5979610df..397e854567 100644
--- a/src/guide/migration.md
+++ b/src/guide/migration.md
@@ -37,58 +37,3 @@ It depends on a few factors:
> If I upgrade to Vue 3, will I also have to upgrade Vuex and Vue Router?
[//]: # 'TODO: still need to see where this lands'
-
-## Built-in Directives
-
-### `v-model` API Change
-
-In Vue 2, the `v-model` directive required developers to always use the `value` prop. And if developers required different props for different purposes, they would have to resort to using `v-bind.sync`. In addition, this hard-coded relationship between `v-model` and `value` led to issues with how native elements and custom elements were handled.
-
-However, with Vue 3, the API for two-way data binding is being standardized in order to reduce confusion and to allow developers more flexibility with the `v-model` directive.
-
-Using v-model in Vue 3
-In Vue 3, by detaching the `v-model` from the `value` prop, developers now have the ability to pass arguments to `v-model` which will allow them to create multiple `v-model` bindings on a single component.
-
-```html
-
-```
-
-#### Modifiers
-
-In Vue 2.x, hard-coded modifiers such as `.trim` on `v-model` were introduced to provide an intuitive way to solve common scenarios. However,
-
-[//]: # 'TODO: still need to finish, and perhaps add in caveats'
-
-### `v-model.sync` Replaced with `v-model` Argument
-
-In Vue 2, the `.sync` modifier was created in order to offer a shorthand way to create two-way data binding for a prop. For example, in the event we want a child component to update its own title property, we would have done something like this:
-
-**ChildComponent.vue**
-
-```html
-this.$emit('onUpdate:title', newTitle)
-```
-
-**ParentComponent.vue**
-
-```html
-
-```
-
-However, this led to some confusion since two-way data flow is closely tied to the `v-model` directive, whereas `v-bind` is normally used for one-way data flow for props.
-
-#### How to Sync Props in Vue 3
-
-In Vue 3, we no longer need the `.sync` modifier anymore. Similar to how we can listen for changes to a form input value, Vue 3 allows us to perform "two way data binding" on props by allowing you to pass the prop as an argument to `v-model`.
-
-
-
-Using the example from before, it can now be simplified to:
-
-**ParentComponent.vue**
-
-```html
-
-```
-
-By passing our prop title to the `v-model` directive, Vue will listen for an `onUpdate:title` event that will be emitted from the child component in order to update the data accordingly.
diff --git a/src/guide/migration/v-model.md b/src/guide/migration/v-model.md
new file mode 100644
index 0000000000..fef5daf1e4
--- /dev/null
+++ b/src/guide/migration/v-model.md
@@ -0,0 +1,147 @@
+# Changes to `v-model` on custom components
+
+## Overview
+
+In terms of what has changed, at a high level:
+
+- When used on custom components, `v-model` prop and event default names are changed:
+ - prop: `value` -> `modelValue`;
+ - event: `input` -> `update:modelValue`;
+- Multiple `v-model` bindings on the same component are possible now;
+- **BREAKING:** `v-bind`'s `.sync` modifier and component `model` option are removed and replaced with an argument on `v-model`;
+- **NEW:** Added the ability to create custom `v-model` modifiers.
+
+For more information, read on!
+
+## Introduction
+
+In Vue 2, the `v-model` directive required developers to always use the `value` prop. And if developers required different props for different purposes, they would have to resort to using `v-bind.sync`. In addition, this hard-coded relationship between `v-model` and `value` led to issues with how native elements and custom elements were handled.
+
+In 2.2 we introduced the `model` component option that allows the component to customize the prop and event to use for `v-model`. However, this still only allowed a single `v-model` to be used on the component.
+
+With Vue 3, the API for two-way data binding is being standardized in order to reduce confusion and to allow developers more flexibility with the `v-model` directive.
+
+## Previous Syntax
+
+In v2, using a `v-model` on a component was an equivalent of passing a `value` prop and emitting an `input` event:
+
+```html
+
+
+
+
+
+```
+
+If we wanted to change prop or event names to something different, we would need to add a `model` option to `ChildComponent` component:
+
+```html
+
+
+
+```
+
+```js
+// ChildComponent.vue
+
+export default {
+ model: {
+ prop: 'title',
+ event: 'change'
+ },
+ props: {
+ // this allows using the `value` prop for a different purpose
+ value: String,
+ // use `title` as the prop which take the place of `value`
+ title: {
+ type: String,
+ default: 'Default title'
+ }
+ }
+}
+```
+
+So, `v-model` in this case would be a shorthand to
+
+```html
+
+```
+
+### Using `v-bind.sync`
+
+In some cases, we might need "two-way binding" for a prop (sometimes in addition to existing `v-model` for the different prop). To do so, we recommended emitting events in the pattern of `update:myPropName`. For example, for `ChildComponent` from the previous example with the `title` prop, we could communicate the intent of assigning a new value with:
+
+```js
+this.$emit('update:title', newValue)
+```
+
+Then the parent could listen to that event and update a local data property, if it wants to. For example:
+
+```html
+
+```
+
+For convenience, we had a shorthand for this pattern with the .sync modifier:
+
+```html
+
+```
+
+## Current Syntax
+
+In v3 `v-model` on the custom component is an equivalent of passing a `modelValue` prop and emitting an `update:modelValue` event:
+
+```html
+
+
+
+
+
+```
+
+### `v-model` arguments
+
+To change a model name, instead of a `model` component option, now we can pass an _argument_ to `v-model`:
+
+```html
+
+
+
+
+
+```
+
+
+
+This also serves as a replacement to `.sync` modifier and allows us to have multiple `v-model`s on the custom component.
+
+```html
+
+
+
+
+
+```
+
+### `v-model` modifiers
+
+In addition to v2 hard-coded `v-model` modifiers like `.trim`, now v3 supports custom modifiers:
+
+```html
+
+```
+
+Read more about custom `v-model` modifiers in the [Custom Events](../component-custom-events.html#handling-v-model-modifiers) section.
+
+## Next Steps
+
+For more information on the new `v-model` syntax, see:
+
+- [Using `v-model` on Components](../component-basics.html#using-v-model-on-components)
+- [`v-model` arguments](../component-custom-events.html#v-model-arguments)
+- [Handling `v-model` modifiers](../component-custom-events.html#v-model-arguments)