Capítulo 22 de 29

Chapter 22: SSR & Meta-Frameworks

Core Idea

TanStack Start, Next.js App Router, and Remix each get a dedicated package (ch002) implementing the same three-step pattern: validate submitted FormData on the server with createServerValidate, run that validation inside that framework's own server-action mechanism, and merge the server result back into the client form with useTransform + mergeForm.

Key Concepts

  • Server-side validation: createServerValidate builds a serverValidate function that checks incoming FormData before it's persisted, throwing a ServerValidateError on failure in every one of the three integrations.
  • Form actions, per framework:
    • TanStack Start: a createServerFn-based server function receives FormData, validates, and returns errors or a success result.
    • Next.js: a React Server Action ('use server') plays the same role, invoked via useActionState on the client.
    • Remix: a route's exported action receives FormData from the POST and is read back via useActionData.
  • Hydration/merging: in all three, the client obtains server state (via a loader's getFormDataFromServer() for Start, useActionState's return for Next.js, useActionData for Remix) and merges it into the client form with useTransform + mergeForm, so client-side validation layers cleanly on top of server-validated state instead of overwriting it.

Reference Tables

FrameworkServer entry pointClient read-back
TanStack StartcreateServerFn + createServerValidateloader → getFormDataFromServer()
Next.js App RouterServer Action ('use server') + createServerValidateuseActionState
Remixroute action export + createServerValidateuseActionData

Worked Example

Across all three frameworks the shape is: define serverValidate = createServerValidate({ ...validation config... }) once, call it inside the framework's server entry point (server function / server action / route action) against the incoming FormData, and catch ServerValidateError to return the failed state back to the client instead of letting it throw uncaught. On the client, useForm is created as usual, then useTransform(mergeForm(...), [serverState]) (or the equivalent read-back for that framework) layers the server's validation result onto the client form's own state — so a page that fails progressive-enhancement (JS not yet loaded, or a slow client) still gets correct server-validated error messages on first paint, and once hydrated, the same form continues validating client-side via the normal validators (ch008) mechanism.

Key Takeaways

  1. Install the framework-specific package (@tanstack/react-form-start/-nextjs/-remix, ch002) — don't hand-roll createServerValidate wiring against the generic core.
  2. ServerValidateError is the control-flow signal for "validation failed on the server" — always catch it explicitly rather than letting a validation failure surface as an unhandled 500.
  3. mergeForm (ch026) is the piece that actually reconciles server and client state — reach for ch026 when the merge behavior itself (not the framework wiring) is what needs debugging.

Connects To

  • Ch017 Submission Handling: the client-side handleSubmit this server validation complements, not replaces.
  • Ch026 Field & Form API Classes: mergeForm's mechanics in more depth.
  • Ch002 Installation: the three framework-specific packages this chapter assumes are installed.