Form Validation Explained: Client-Side, Server-Side, and Why You Need Both
Validation checks that what users type makes sense before you save it. The difference between browser-side and server-side validation, why only the server's counts for security, built-in HTML validation, sharing rules with a schema, and writing error messages people understand.
Every form in your app — sign-up, checkout, settings, contact — needs validation: checking that what people submit makes sense before you save or act on it. AI-built apps often have validation that looks thorough, and protects almost nothing. The difference is where it runs.
Two places validation happens
Client-side: in the browser
Checks that run in the user's browser, before the form is sent:
- "Email is required."
- "Password must be at least 12 characters."
- Red outlines and messages appearing as you type.
Purpose: a good user experience. Instant feedback, no waiting for the server.
Server-side: on your backend
Checks that run on your server when the data arrives, before it's saved.
Purpose: correctness and security.
Why only the server's validation counts
Client-side validation is trivially bypassed. Anyone can:
- Turn off JavaScript.
- Edit the page in DevTools and remove the
requiredattribute. - Skip your form entirely and send a request straight to your API with any data they like —
curl, a script, or a browser's Network tab "edit and resend."
So the browser's validation is a courtesy to honest users. The server must re-check everything, as if the front end didn't exist. (Frontend vs Backend.)
A classic AI-built-app bug: the sign-up form limits usernames to 20 letters, but the API accepts 50,000 characters of anything — including HTML that breaks every page it's displayed on. (What Is XSS?.)
What to validate on the server
For every field:
- Present? Required fields exist.
- Right type? A number is a number; a date is a date.
- Right format? An email looks like an email; a postcode fits the pattern.
- Right size? Minimum and maximum lengths; numbers within a sensible range. (No negative quantities, no 10 MB "names.")
- Allowed values? A
planfield is one offree,pro,team— nothing else. - Allowed for this user? The user can't set fields they shouldn't:
isAdmin,price,ownerId,credits. Only accept the fields the form is meant to change. (Authentication vs Authorization.)
And some checks only the server can do:
- Is the email already taken?
- Does this coupon exist and is it still valid?
- Is the item in stock?
Built-in browser validation
HTML has free validation built in — use it for the client-side part:
<form>
<label for="email">Email</label>
<input id="email" name="email" type="email" required>
<label for="age">Age</label>
<input id="age" name="age" type="number" min="13" max="120">
<label for="username">Username</label>
<input id="username" name="username" required minlength="3" maxlength="20"
pattern="[a-z0-9_]+">
<button>Sign up</button>
</form>
type="email" also brings up the right keyboard on phones. (Regular Expressions for Beginners explains pattern.)
One set of rules, used in both places
Writing the same rules twice — once for the browser, once for the server — means they drift apart. The modern approach is a schema: define the rules once, and use them in both places. In TypeScript projects, Zod is the common choice:
import { z } from "zod"
export const signUpSchema = z.object({
email: z.string().email(),
username: z.string().min(3).max(20).regex(/^[a-z0-9_]+$/),
age: z.number().int().min(13).max(120),
})
The browser uses it for instant feedback; the server uses the same schema to check the request before touching the database. (Validating Input With Zod goes further.)
Error messages people understand
Validation is also a conversation with your users. Good messages:
- Say what's wrong and how to fix it. "Password must be at least 12 characters" beats "Invalid password."
- Appear next to the field, not only in a banner at the top.
- Keep what the user typed. Don't clear the whole form because one field was wrong.
- Don't blame. "Please enter a date in the future" beats "Invalid input!"
- Are accessible — connected to the field for screen readers, not just shown as a red border. (Web Accessibility Basics.)
- Don't reveal too much. On login and password reset, don't confirm whether an email has an account.
Don't over-validate
Some validation annoys real users for no benefit:
- Names — people's names contain apostrophes, hyphens, spaces, accents, and non-Latin characters. Don't restrict them to
A–Z. - Email — perfect email validation is impossible. Do a light check and send a confirmation email.
- Phone numbers and addresses — formats vary enormously between countries.
- Password rules — long passphrases beat forced symbol-and-number combinations. Allow paste, so password managers work.
The checklist
- Every form's data is validated again on the server
- Types, formats, lengths, and ranges are checked
- Users can't set protected fields
- Rules are defined once (a schema) and shared
- Errors are specific, next to the field, and keep the user's input
- Names, emails, and phone numbers aren't over-restricted
EasySpawn runs your app's backend as a real server, so server-side validation has somewhere to live — and Claude Code can test it by sending the bad requests an attacker would. See how it works for AI-built apps or join the waitlist.
Related: SQL Injection Explained · What Is CRUD? · A Security Checklist for Vibe-Coded Apps · How to Add a Contact Form
Keep reading
Do You Need a Cookie Banner? A Plain-English Guide for Small Apps
Cookie banners are required when you set non-essential cookies or trackers for EU and UK visitors — not for every cookie. What counts as essential, when you need consent, what a compliant banner must do, and how to avoid needing one at all.
The OWASP Top 10 (2025) Explained for Beginners and App Builders
The OWASP Top 10 is the most widely used list of web application security risks. All ten 2025 categories in plain English — from broken access control to supply chain failures — with what each looks like in an AI-built app and how to prevent it.