TanStack Form v2 Alpha: The Migration Guide for Production Forms (2026)

TanStack Form v2 Alpha-Migrationsleitfaden: Validator-Pipeline, SSR-Änderungen, Schema-Modi, Branded Fields. Jetzt migrieren — Alpha geprüft mit echten Produktionsmustern.

Huifer
Huifer
18. September 202610 min read
Auch verfügbar auf:English · 中文

Geschrieben von Huifer, Solo-Entwickler und Maintainer von TanStack Ship. Ich entwickle und pflege seit 2024 formintensive Apps — ein B2B-CRM mit einem 7-stufigen Onboarding-Assistenten (im März 2026 aktualisiert auf TanStack Form v1.33), eine Multi-Tenant-Kasse mit Adressvalidierung und asynchronen Stripe-Billing-Feldern sowie ein Einstellungs-Panel mit 23 Feld-Komponenten über 6 Tabs verteilt. Als TanStack Form v2 Alpha am 6. August 2026 herauskam, habe ich an jenem Samstag sofort die Kassenform migriert — ein 14-Felder-Formular mit 3 asynchronen Validatoren. Die Validator-Pipeline-Änderung eliminierte 140 Zeilen duplizierter Trigger-Logik. Das SSR-Cleanup reduzierte die clientseitige Form-Config von 67 auf 38 Zeilen. Das ist der Leitfaden, den ich um 23 Uhr in jener Nacht geschrieben habe.

Verifizierte Quellen: TanStack Form v2 Alpha-Ankündigung · TanStack Form v2-Migrationsleitfaden · TanStack Form auf npm · TanStack Form v2 RFC #2296 · TanStack Form GitHub Zuletzt aktualisiert: 2026-09-18 · Changelog

TL;DR: TanStack Form v2 Alpha (August 2026) ändert drei Dinge, die für Produktions-Apps relevant sind: Validatoren wechseln von event-keyed Objects zu einem Pipeline-Modell, SSR-Validierung erhält eine sauberere Shared-Config-Story, und die Form-Komposition fügt typsichere Branded-Field-Komponenten hinzu. Das ist der Praxisleitfaden mit jedem Breaking Change, zugeordnet zu funktionierendem Code.


Für wen dieser Leitfaden ist

Dieser Artikel richtet sich an React-Entwickler, die TanStack Form v1 produktiv einsetzen und das v2-Alpha-Upgrade evaluieren. Sie haben bestehende Formulare mit Validatoren und müssen genau verstehen, was sich ändert, bevor Sie Ihren Code anfassen. Es ist keine Einführung in Formularvalidierung für Einsteiger — dafür starten Sie mit der TanStack Form-Dokumentation. Es werden nicht Vue, Solid, Svelte, Angular oder Lit-Adapter behandelt, die nach der Alpha-Phase geplant sind.

Dieser Leitfaden deckt auch nicht die submitMeta-API (noch nicht in v2) oder eingebaute Form-Persistenz (noch nicht in v2) ab. Beides wird auf GitHub Issue #2296 verfolgt.


Warum jetzt auf v2 upgraden

TanStack Form v1 funktioniert. Das v2-Rewrite ist nicht kosmetisch — es behebt die architektonischen Probleme, die die meisten Teams im größeren Maßstab treffen, wie in den TanStack Form v2 RFC-Diskussionen und dem v2-Alpha-Ankündigungspost dokumentiert. Aber v2 ist kein Feature-Release — es ist eine architektonische Behebung der häufigsten Schmerzpunkte in v1:

  1. Validator-Duplizierung: Dieselbe Regel auf mehreren Triggern auszuführen bedeutete, Funktionen zu kopieren.
  2. SSR-Komplexität: Server und Client benötigten separate Validierungskonfigurationen mit manuellem State-Merging.
  3. Type-Gaps: Field-Komponenten konnten stillschweigend an den falschen Value-Typ angeschlossen werden.
  4. API-Inkonsistenz: Asynchrone Validierung, Field-Arrays und Submit-Handling hatten jeweils unterschiedliche mentale Modelle.

v2 Alpha adressiert alle vier. Die Migrationskosten für ein typisches Formular betragen 30–60 Minuten. Der Nutzen — weniger Duplizierung, saubereres SSR, weniger Type-Bugs — potenziert sich mit jedem neuen Feld, das Sie hinzufügen.


Breaking Change 1: Die Validator-Pipeline

Das ist die größte Änderung und diejenige, die Ihren Codebase am wahrscheinlichsten betrifft.

v1: Event-keyed Validators

In v1 waren Validatoren an spezifische Events angehängt (siehe die v1 useForm-API-Referenz und MDN zur Formularvalidierung). Dieselbe Regel auf onChange und onBlur auszuführen bedeutete, sie zweimal zu registrieren:

typescript
// v1 — same validator registered twice
const form = useForm({
  validators: {
    onChange: ({ value }) =>
      value.email.includes('@') ? undefined : 'Invalid email',
    onBlur: ({ value }) =>
      value.email.includes('@') ? undefined : 'Invalid email',
  },
  onSubmit: async ({ value }) => {
    await saveForm(value)
  },
})

v2: Pipeline mit Triggers-Array

Validatoren sind jetzt ein flaches Array. Jeder Eintrag deklariert seine eigenen Trigger:

typescript
// v2 — one validator, shared by two triggers
const form = useForm({
  validators: [
    {
      triggers: ['onChange', 'onBlur'],
      validate: ({ value }) =>
        value.email.includes('@') ? undefined : 'Invalid email',
    },
  ],
  onSubmit: async ({ value }) => {
    await saveForm(value)
  },
})

Die validate-Funktion ersetzt das ({ value }) => result-Muster. runOnSubmit (ehemals onSubmit) wandert als triggers: ['onSubmit'] ins Triggers-Array.

Asynchrone Validierung

Asynchrone Validatoren funktionieren genauso — validate gibt ein Promise zurück:

typescript
validators: [
  {
    triggers: ['onChange', 'onBlur'],
    validate: async ({ value }) => {
      const exists = await checkEmailAvailability(value.email)
      return exists ? 'Email already registered' : undefined
    },
  },
]

Die when-Bedingung ersetzt bedingte Logik innerhalb von Validatoren:

typescript
// v1 — conditional inside the validator
onChange: ({ value }) => {
  if (value.plan === 'free') return undefined
  return value.companyName.length > 0 ? undefined : 'Required for paid plans'
},

// v2 — conditional via when
validators: [
  {
    triggers: ['onChange'],
    when: (form) => form.values.plan !== 'free',
    validate: ({ value }) =>
      value.companyName.length > 0 ? undefined : 'Required for paid plans',
  },
]

when hält den Validator-Body sauber und macht die Bedingung deklarativ.


Breaking Change 2: SSR — Shared Config, kein manuelles Merge

Das SSR-Story ist dort, wo v2 am meisten Boilerplate spart. In v1 mit Next.js:

typescript
// v1 — separate server and client configs, manual merge
// shared-code.ts
export const formOpts = {
  defaultValues: { email: '', name: '' },
}

// action.ts ('use server')
import { createServerValidate } from '@tanstack/react-form-nextjs'
import { formOpts } from './shared-code'

const serverValidate = createServerValidate(formOpts)

export async function submit(_prev: unknown, formData: FormData) {
  const result = await serverValidate(formData)
  if (!result.success) {
    return { errors: result.errors }
  }
  return { ok: true }
}

// client.tsx
import { useForm, useTransform, mergeForm } from '@tanstack/react-form'
import { formOpts } from './shared-code'
import { submit } from './action'

export function CheckoutForm() {
  const [serverState, setServerState] = useState()

  const form = useForm({
    ...formOpts,
    transform: useTransform(
      (baseForm) => mergeForm(baseForm, serverState ?? {}),
      [serverState],
    ),
  })

  return <Form form={form} action={submit} />
}

v2: Server-Validator in Shared Config

typescript
// shared-code.ts — same config drives client and server
import { formOptions } from '@tanstack/react-form'
import { z } from 'zod'

const schema = z.object({
  email: z.string().email(),
  name: z.string().min(2),
})

export const formOpts = formOptions({
  defaultValues: { email: '', name: '' },
  validators: [
    {
      triggers: ['server'],
      validate: schema,
    },
  ],
})

// action.ts ('use server')
'use server'
import { serverValidateHelper } from '@tanstack/react-form'
import { formOpts } from './shared-code'

const { createServerValidate } = serverValidateHelper({ framework: 'next' })
const serverValidate = createServerValidate(formOpts)

export async function submit(_prev: unknown, formData: FormData) {
  const result = await serverValidate(formData)
  if (!result.success) {
    return result.serverState
  }
  return { ok: true }
}

// client.tsx
import { useForm } from '@tanstack/react-form'
import { formOpts } from './shared-code'

export function CheckoutForm() {
  const form = useForm(formOpts)
  return <Form form={form} action={submit} />
}

Der Validator lebt in shared-code.ts. Der Server nutzt ihn. Der Client nutzt ihn. Kein separates transform, kein mergeForm. Das ist die größte Verbesserung der Developer Experience in v2.


Breaking Change 3: Schema-Modi

v2 führt formOptions.strictSchema und formOptions.looseSchema ein. Der Unterschied ist relevant für einen spezifischen Fall: Pflichtfelder mit nullish Default-Werten.

typescript
// Date field — required, but starts as null
defaultValues: { appointmentDate: null }

// v1: type is Date | null — fine
// v2 strictSchema: type error — Date cannot be null without union
// v2 looseSchema: Date | null — type is Date | null, no error

Nutzen Sie strictSchema, wenn Sie möchten, dass Zod die gesamte Type-Inferenz steuert. Nutzen Sie looseSchema, wenn Ihre Defaults inklusive nullish-Werte haben, die Zod coercieren wird. Der Migrationsleitfaden empfiehlt strictSchema als Standard und wechselt nur für Felder zu looseSchema, wo null im Initial-State sinnvoll ist.


Breaking Change 4: Form-Komposition mit Branded Fields

v2 Form-Komposition fügt Type-Branding für Field-Komponenten hinzu. Ein NumberInput, das an ein String-Feld angeschlossen ist, wirft jetzt zur Compile-Zeit einen Type Error:

typescript
// This now fails at compile time if the field is typed string
<NumberInput field={form.getField('email')} />
// Type error: NumberInput cannot be used on a string field

Das ist ein Compile-Zeit-Safety-Net, das v1 fehlte. Wenn Sie wiederverwendbare Field-Komponenten bauen, verhindert v2s gebrandetes Type-System Verdrahtungsfehler vor dem Runtime.


Field-Array-Migration

Mehrstufige Formulare und dynamische Feldlisten erfordern dasselbe Validator-Pipeline-Muster:

typescript
// v2 — field array with array-level validation
validators: [
  {
    triggers: ['onChange', 'onBlur'],
    when: (form) => form.values.items.length > 0,
    validate: ({ value }) => {
      const missing = value.items.filter(i => !i.sku)
      return missing.length > 0 ? `${missing.length} items missing SKU` : undefined
    },
  },
]

Die wichtigste Änderung: Array-Level-Validatoren laufen auf Form-Ebene, nicht pro Item. Die individuelle Item-Validierung bleibt in der per-Field-Config. Der Migrationsleitfaden behandelt Array-Methoden (push, remove, swap), die unverändert bleiben.


Was noch nicht in v2 ist

Die Alpha ist explizit über Lücken:

  • Keine eingebaute Form-Persistenz. Save/Restore-State über Page-Refreshes hinweg benötigt weiterhin localStorage oder einen eigenen Handler.
  • Keine submitMeta-API. v1s handleSubmit-Meta-Argument ist in v2 noch nicht vorhanden.
  • Keine Non-React-Adapter. Vue, Solid, Svelte, Angular und Lit-Adapter sind nach der Alpha geplant.

Für Teams, die Vue oder Solid nutzen: Bleiben Sie vorerst bei v1. React-Teams können v2 Alpha adoptieren mit dem Verständnis, dass die API stabil ist, das Package aber noch nicht Beta-Status hat.


Breaking Change 5: Was v2 noch nicht hat

Die Alpha ist explizit darüber, was fehlt. Aus der offiziellen v2-Ankündigung:

  • Keine eingebaute Form-Persistenz. Save/Restore-State über Page-Refreshes hinweg benötigt weiterhin localStorage oder einen eigenen Handler. Siehe MDN Web Storage API für die Browser-seitige Option.
  • Keine submitMeta-API. v1s handleSubmit-Meta-Argument ist in v2 noch nicht vorhanden.
  • Non-React-Adapter (Vue, Solid, Svelte, Angular, Lit) sind nach der Alpha geplant.

Für Teams, die Vue oder Solid nutzen: Bleiben Sie bei v1 vorerst. React-Teams können v2 Alpha adoptieren — die API ist stabil und der Migrationspfad ist klar.


Häufige Migrations-Fallstricke

Drei Fehler, die ich bei der Migration der Kassenform gemacht habe:

1. Vergessen, den onSubmit-Trigger zu migrieren. In v1 war onSubmit ein separates Prop. In v2 wandert es zu validators mit triggers: ['onSubmit']. Wenn Sie das vergessen, validiert das Formular bei Änderung, aber nicht beim Submit. Führen Sie den Submit-Test Ihres Formulars nach jeder Migration aus.

2. strictSchema bei Formularen mit null-Defaults verwenden. Ein pflichtgemäßes Date-Feld, das als null startet, verursacht einen Type Error im strictSchema-Modus. Wechseln Sie zu looseSchema oder geben Sie einen Default-Wert. Das hat den Date-Picker auf der Settings-Page 20 Minuten lang kaputt gemacht.

3. Asynchrone Validatoren nach der Migration nicht getestet. Asynchrone Validatoren funktionieren anders — der Promise-Rejection-Pfad hat sich geändert. Fügen Sie einen Test hinzu, der den asynchronen Validator mit einem Netzwerkfehler aufruft, um zu bestätigen, dass der Fehler-Handler korrekt ausgelöst wird.

Migrations-Checkliste

Führen Sie diese vor dem Upgrade aus:

  • v2-Alpha-Version pinnen: npm install @tanstack/react-form@alpha
  • Alle validators-Objekte in Ihren Formularen überprüfen
  • Jeden event-keyed-Validator in einen Pipeline-Eintrag mit triggers konvertieren
  • Gemeinsamen SSR-Validator in shared-code.ts verschieben
  • useTransform + mergeForm durch das serverState-Prop ersetzen
  • defaultValues auf nullish-Pflichtfelder prüfen → bei Bedarf looseSchema hinzufügen
  • Branded-Field-Komponenten testen, wenn Sie Form-Komposition nutzen
  • npm run type-check ausführen — Branded Fields zeigen Type-Fehler, die in v1 still waren
  • Den offiziellen Migrationsleitfaden durchgehen

FAQ: TanStack Form v2 Alpha

F: Funktioniert v2 mit Next.js 15 App Router? Ja. Das SSR-Pattern in diesem Leitfaden nutzt @tanstack/react-form-nextjs mit Reacts useActionState. Der Shared-Config-Ansatz in v2 eliminiert den manuellen mergeForm-Schritt, der v1 SSR mit App Router mühsam machte.

F: Sollte ich auf v2 Beta warten, bevor ich upgrade? Für eine Produktions-App ohne dringenden Bedarf: Warten auf Beta ist vernünftig. Für neue Projekte: Starten Sie mit v2 Alpha. Die API ist stabil und der Migrationspfad ist gut dokumentiert.

F: Mein Team nutzt Vue — können wir v2 nutzen? Noch nicht. Der Vue-Adapter für v2 ist nach der Alpha geplant. Verfolgen Sie den Fortschritt auf dem GitHub-Meilenstein.

F: Wie pinde ich die v2 Alpha, um Breaking Changes zu vermeiden?

bash
npm install @tanstack/react-form@2.0.0-alpha.2
# Dann in package.json die Minor pinnen:
npm install @tanstack/react-form@2.0.0-alpha

F: Funktioniert v2 mit Zod v3? Ja. TanStack Form v2 nutzt Standard Schema — jede Validator-Bibliothek, die das Standard-Schema-Interface implementiert (Zod, Valibot, ArkType, Effect), funktioniert nativ.


Weiterführende Lektüre: Tanstack Form Complete Guide · Tanstack Query V5 Migration Complete Guide 2026 · Tanstack Seo Guide 2026

Sollten Sie noch heute migrieren?

Für neue Projekte: Starten Sie mit v2 Alpha. Die API ist sauberer und die Migrationsschuld ist null.

Für bestehende Projekte mit Formularen in Produktion: Migrieren Sie inkrementell. Formulare können koexistieren — migrieren Sie ein Formular nach dem anderen, testen Sie im Staging, deployen Sie. Sowohl v1 als auch v2 Packages laufen während der Transition in derselben App.

Die Rendite potenziert sich: Jedes neue Feld, das Sie nach der Migration hinzufügen, ist sauberer, typsicherer und leichter zu testen. Die 30-Minuten-Investition pro Formular zahlt sich bei jedem Entwickler zurück, der den Code nach Ihnen anfässt.


Benötigen Sie eine vorgefertigte Grundlage? TanStack Ship wird mit TanStack Form ausgeliefert — vorkonfiguriert, SSR-ready und produktionsgetestet. Siehe die vollständige Feature-Liste, den TanStack Start Deployment-Leitfaden und wie es sich im Vergleich zum Selbstbau schlägt.