Back to Blog
Lesson 18 of the Next.js: Build Full-Stack Apps with the App Router course
Next.jsAugust 5, 20264 min read

Form Validation and Feedback: A Practical Guide for Next.js

Learn to implement secure server-side validation in Next.js. Master returning feedback to the client and displaying error messages to improve data integrity.

Next.jsFormsValidationSecurityWeb Development

Previously in this course, we covered Building a Newsletter Sign-up Form in Next.js using Server Actions. While that setup handles form submission, it lacks a critical piece of production-ready software: ensuring the data entering your system is actually valid.

In this lesson, we are going to move beyond "happy path" programming. You'll learn how to validate inputs on the server, return structured feedback to the client, and display those errors so your users know exactly what went wrong.

Why Server-Side Validation is Essential

Validation is the primary gatekeeper for your application's security and data integrity. While client-side validation (like the required attribute on an <input>) is great for UX, it is easily bypassed by bots or malicious actors.

By performing validation within your Server Actions, you ensure that regardless of how the request is sent, your database only ever sees clean, expected data.

Implementing Server-Side Validation

A close-up view of PHP code displayed on a computer screen, highlighting programming and development concepts.

To validate inputs, we need a way to check the data against a set of rules. A common pattern in the Node.js ecosystem is to return a "state" object from our Server Action.

Let's update our newsletter sign-up action to include basic validation.

TYPESCRIPT
CE9178">'use server'

export async function subscribeToNewsletter(prevState: any, formData: FormData) {
  const email = formData.get(CE9178">'email') as string;

  // Simple validation logic
  if (!email || !email.includes(CE9178">'@')) {
    return {
      success: false,
      message: CE9178">'Please provide a valid email address.',
      errors: { email: CE9178">'Invalid email format' }
    };
  }

  // Simulate database logic
  console.log(CE9178">'Subscribing:', email);

  return { success: true, message: CE9178">'Successfully subscribed!' };
}

Providing Feedback to the Client

Next.js provides the useFormState hook (now often referred to as useActionState in newer versions) to handle the returned state from your action. This allows your component to react to the server's response.

You'll need to wrap your form component in "use client" to utilize this hook.

TSX
CE9178">'use client'
import { useActionState } from CE9178">'react';
import { subscribeToNewsletter } from CE9178">'./actions';

export default function NewsletterForm() {
  const [state, formAction] = useActionState(subscribeToNewsletter, null);

  return (
    <form action={formAction}>
      <input name="email" type="email" />
      {state?.errors?.email && <p className="text-red-500">{state.errors.email}</p>}
      
      {!state?.success && state?.message && <p>{state.message}</p>}
      {state?.success && <p className="text-green-500">{state.message}</p>}
      
      <button type="submit">Subscribe</button>
    </form>
  );
}

Common Pitfalls

When implementing validation, keep these three traps in mind:

  1. Trusting the Client: Never assume that because an input has a required attribute, the data arriving at your Server Action is present. Always validate on the server.
  2. Generic Error Messages: Telling a user "Something went wrong" is frustrating. Be specific—tell them which field failed and why.
  3. Forgetting Accessibility: Ensure your error messages are associated with the input fields using aria-describedby so screen readers announce the error when a user focuses on the field.

Hands-on Exercise

Refactor your existing newsletter form:

  1. Update your action to return a formal errors object.
  2. Implement the useActionState hook in your component.
  3. Display error messages conditionally below the relevant input field.
  4. Add an extra validation rule, such as checking if the email length is at least 5 characters.

FAQ

Q: Should I still use client-side validation? A: Absolutely. Use HTML5 attributes or libraries like Zod for real-time, snappy user feedback, but always treat it as a secondary layer. Your server is the final source of truth.

Q: Can I use libraries for validation? A: Yes. Many production apps use Zod to define schemas and validate FormData objects concisely. It prevents the manual if/else boilerplate we used above.

Q: Where should I display the error? A: Place the error message as close to the relevant input as possible to maintain context for the user.

Recap

Team members presenting a project in a modern office setting with a focus on collaboration.

In this lesson, we established that validation is a non-negotiable part of secure development. By returning structured state from Server Actions and consuming it with useActionState, we create a resilient bridge between our user's intent and our data storage. These patterns are essential for avoiding Secure Multi-Part Form Data vulnerabilities and maintaining a high-quality user experience.

Up next: We’ll move into the data layer by performing a Database Setup with Prisma.

Similar Posts