Validating form data in Remix using Zod and Action function

In this tutorial, we'll learn how to use the Zod and Action function to validate form data in Remix.

Zod is a schema validation library for TypeScript. It allows us to define a schema for our data and validate it against the schema.

When you make a POST request to your route, you can use the Action function to validate the data before it's processed.

Let's add a new route to our app called /signup and handle the form submission.

Add the following code to app/routes/signup.tsx:

import type { ActionArgs } from "@remix-run/node";
import { Form, useActionData } from "@remix-run/react";
import { redirect, json } from "@remix-run/node";

import { z } from "zod";

export async function action({ request }: ActionArgs) {
  // Get the form data from the request
  const formData = Object.fromEntries(await request.formData());

  // Define the schema for the form data
  const schema = z.object({
    name: z.string().min(1),
    email: z.string().email(),
    password: z.string().min(8),

  // Validate the form data against the schema
  const parsed = schema.safeParse(formData);

  // If the validation fails, return the errors to the client
  if (!parsed.success) {
    return json({ error: parsed.error.format() });

  // If the validation succeeds, get the data from the parsed object
  const newUser =;


  // Use the `newUser` object to create a new user in your database

  return redirect("/signup");

export default function User() {
  // Get the form validation errors returned from the server
  const data = useActionData<typeof action>();

  return (
      <h1>Create a new user</h1>
      <Form method="post">
        <input type="text" name="name" placeholder="Name" />
        {data && && <p>{[0]}</p>}
        <input type="email" name="email" placeholder="Email" />
        {data && && <p>{[0]}</p>}
        <input type="password" name="password" placeholder="Password" />
        {data && data.error.password && <p>{data.error.password._errors[0]}</p>}
        <button type="submit">Create User</button>

You can use useActionData to get the data returned from the server. In this case, we're getting the form validation errors.

const data = useActionData<typeof action>();

We can then use the data.error object to display the validation errors on the client.

Here is the output when the form is submitted with invalid data:

  _errors: [],
  name: { _errors: [ 'String must contain at least 1 character(s)' ] },
  email: { _errors: [ 'Invalid email' ] },
  password: { _errors: [ 'String must contain at least 8 character(s)' ] }

That's it! You can now validate form data in Remix using Zod and Action function.

More Articles

  1. Use Remix Action to handle form submission
  2. Use Remix Loader to fetch data from an external API
  3. Validating form data in Remix using Zod and Action function
  4. Add a search form in Remix with data fetching
  5. Show a flash message in Remix after form submission
  6. Discover the best SaaS Starter Kits based on Remix