Ask
61
@dax_darian ·

zod in the action or react-hook-form on the client, solo and launching in two weeks Validation

Six forms, the biggest has nine fields. I keep starting react-hook-form + a resolver, then remembering the action has to validate anyway, then wondering why I'm writing it twice. Two weeks until I need this in front of people and I am one person. What do you actually do here?

8 answers Share
Report

Answering anonymously — a moderator will review it first.

  • @listener_lena · 3mo ago · 2 replies

    Server first, always, because the action is a public endpoint and client validation is a UX feature. One schema in a plain file both sides can import, safeParse in the action, errors back through useActionState:

    const parsed = createOrder.safeParse(Object.fromEntries(formData))
    if (!parsed.success) return { errors: z.flattenError(parsed.error).fieldErrors }
    

    The field error shape maps straight onto your inputs by name. For nine fields that is the whole implementation. Add react-hook-form later if a form gets long enough that a round trip per validation feels bad.

    84
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
    • @query_quinn · 3mo ago

      Worth knowing that flatten-style output only gives you the top level. If you have nested objects or arrays of line items, go straight to the tree/issue list and key errors by path — trying to flatten a nested schema is where people give up and reach for a library.

      24
      Share
      Reply

      Answering anonymously — a moderator will review it first.

      Report
  • @crypt_cass · 3mo ago

    Decide per form, not per app. Four fields, submit-and-see: plain action. A twenty-field wizard with cross-field rules and a live total: react-hook-form, because sending a round trip on every keystroke to validate "end date after start date" is miserable. You have neither of those, you have nine fields.

    46
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
  • @leech_wrangler · 3mo ago

    Two weeks: ship the server-only version. You will redo the form UI once real people use it anyway, and you will redo it with actual complaints instead of guesses about which fields confuse them.

    29
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
  • @mise_en_mess · 3mo ago

    One practical thing: put the schemas in lib/schemas.ts with no 'use server' at the top. If you export them from the same file as the actions you end up either importing a server module into a client component or duplicating the schema, and both of those get ugly fast.

    18
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
  • @capsule_curious · 3mo ago · 2 replies

    next-safe-action and Conform both sit in the middle and are genuinely nice. Being honest though: they are another dependency and another set of docs to read, and at nine fields you will finish faster without them.

    12
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
    • @dax_darian · 3mo ago

      Went with plain useActionState and a shared schema file. Forty minutes for all six forms including the error rendering. Noting it here in case someone finds this later wondering whether the simple version is really enough at this size — it is.

      9
      Share
      Reply

      Answering anonymously — a moderator will review it first.

      Report
  • @iron_camber · 3mo ago

    Whatever you pick, validate the same schema in a test that posts garbage to the action directly. It is the only test in this area that has ever caught anything for me.

    7
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report