---
title: "Migrating from NotForm v3"
description: "Update NotForm v3 code to v4: renamed APIs, explicit field instances, moved validation config, and array fields."
canonical_url: "https://notformdocs.vercel.app/docs/migrations/notform-v3"
---

> Index of every page on this site: [llms.txt](https://notformdocs.vercel.app/llms.txt)

NotForm v4 changes the public Vue API. This guide updates forms written with the v3 names `useNotForm`, `NotForm`, `NotField`, `NotArrayField`, and `NotMessage`.

<note>

Check your installed version first. If `notform` in your `package.json` is `3.x`, the rest of these docs describe the version you are migrating to.

</note>

## 1. Rename the APIs

<table>
<thead>
  <tr>
    <th>
      NotForm v3
    </th>
    
    <th>
      NotForm v4
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        useNotForm
      </code>
    </td>
    
    <td>
      <code>
        useForm
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        <NotForm>
      </code>
    </td>
    
    <td>
      <code>
        <Form>
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        <NotField>
      </code>
    </td>
    
    <td>
      <code>
        <Field>
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        <NotArrayField>
      </code>
    </td>
    
    <td>
      <code>
        <ArrayField>
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        <NotMessage>
      </code>
    </td>
    
    <td>
      <code>
        <FieldError>
      </code>
    </td>
  </tr>
</tbody>
</table>

The core package is still `notform`. For Nuxt, use `@notform/nuxt`. Older instructions may reference `notform-nuxt`, so replace that dependency. In Vue, update imports from `notform`. In Nuxt, the module auto-imports the v4 names.

Rename everywhere with a project-wide search and replace on whole words, then fix the structural changes below.

## 2. Pass explicit field instances

In v3, `<NotForm>` provided form context to descendants, so a field could be declared with only a `path`. In v4, `Form` renders the native form but provides no context. Create each field on the form instance and pass it to `Field`.

<code-group>

```vue [v3.vue]
<template>
  <NotForm :form="form">
    <NotField
      v-slot="{ events, path }"
      path="email"
    >
      <input
        v-bind="events"
        :id="path"
        v-model="form.values.email"
        type="email"
        :name="path"
      >

      <NotMessage :path="path" />
    </NotField>
  </NotForm>
</template>
```

```vue [v4.vue]
<template>
  <Form :form="form">
    <Field
      v-slot="{ field }"
      :field="form.field('email')"
    >
      <input
        v-bind="field.events"
        :id="field.path"
        v-model="field.model"
        type="email"
        :name="field.path"
      >

      <FieldError :errors="field" />
    </Field>
  </Form>
</template>
```

</code-group>

The v4 `Field` slot exposes one `field` object. Use `field.model`, `field.events`, `field.path`, and `field.errors` instead of the top-level slot props `events`, `path`, and `errors`. Binding `field.model` also replaces writing to `form.values.email` directly, though that still works.

## 3. Move validation config to the field

v3 field components accepted options such as `validateOn`, `validationMode`, and `debounce` as props. In v4, pass a `FieldConfig` as the second argument when the field is first created.

```ts
const username = form.field('username', {
  debounce: 300,
  validateOn: { input: true },
  validationMode: 'lazy',
})
```

The keys of `validateOn` are `blur`, `change`, and `input`. A field is cached by path, so later calls with different options do not replace the first. See [Validation](https://notformdocs.vercel.app/docs/guides/validation#configure-a-field).

## 4. Update array fields

v3 `NotArrayField` was declared by path. In v4, create an explicit array field, and use `item.id` as the key.

<code-collapse>

```vue
<template>
  <ArrayField
    v-slot="{ arrayField }"
    :array-field="form.arrayField('todos')"
  >
    <div
      v-for="item in arrayField.items"
      :key="item.id"
    >
      <Field
        v-slot="{ field }"
        :field="item"
      >
        <input
          v-bind="field.events"
          :id="field.path"
          v-model="field.model"
          type="email"
          :name="field.path"
        >

        <FieldError :errors="field" />
      </Field>

      <button
        type="button"
        @click="arrayField.remove(item.index)"
      >
        Remove
      </button>
    </div>

    <button
      type="button"
      @click="arrayField.append('')"
    >
      Add
    </button>
  </ArrayField>
</template>
```

</code-collapse>

Each item provides `index`, `path`, `field()`, and `arrayField()` for nested values. Mutations are methods on `arrayField`. See [Array fields](https://notformdocs.vercel.app/docs/guides/array-fields).

## 5. Check the rest of the form

- `Form` requires a `form` prop and does not inject it into descendants.
- `FieldError` takes an issue array or a field-like value through `errors`. It no longer resolves a path from form context.
- `onSubmit` remains a `useForm` option, and `Form` handles native submit and reset.
- `useForm` returns the public API in [useForm](https://notformdocs.vercel.app/docs/composables/use-form). Do not rely on instance members that are not listed there.

## Migration checklist

- [ ] Dependencies updated (`notform`, and `@notform/nuxt` instead of `notform-nuxt`).
- [ ] All `useNotForm`, `NotForm`, `NotField`, `NotArrayField`, and `NotMessage` renamed.
- [ ] Every `Field` receives `:field="form.field(path)"` instead of a `path` prop.
- [ ] Slot props switched to `field.model`, `field.events`, `field.path`, and `field.errors`.
- [ ] `FieldError` receives `:errors="field"`.
- [ ] Validation options moved into `form.field(path, config)`.
- [ ] Array fields use `form.arrayField(path)`, `item.id` keys, and array methods.
- [ ] Type check and lint pass. Mistyped paths are now compile errors.

## Next steps

- [Quickstart](https://notformdocs.vercel.app/docs/getting-started/quickstart) shows a complete v4 form.
- [Core concepts](https://notformdocs.vercel.app/docs/getting-started/core-concepts) explains the model that v4 makes explicit.

## Sitemap

See the full [sitemap](https://notformdocs.vercel.app/sitemap.md) for all pages.
