Validation answer
Client validation improves user experience. Server validation protects the system.
Treat the browser as a helpful client
Form validation is searched constantly because it affects UX and security at the same time.
Divide feedback from enforcement
The browser can help users correct mistakes, but the server must be the source of truth because clients can be bypassed.
| Layer | Job |
|---|---|
| Client | Fast feedback, required fields, friendly formatting |
| Server | Security, uniqueness, permissions, trusted rules |
| Database | Constraints that protect data permanently |
Trace one signup request
const email = formData.get("email");
if (typeof email !== "string" || !email.includes("@")) {
return { ok: false, field: "email", message: "Enter a valid email." };
}
This example is intentionally small. In a real codebase, the surrounding details matter: naming, error handling, tests, runtime config, permissions, and how easy the next developer can understand the change.
Validate again at the state boundary
- Validate on submit server-side.
- Show client errors before submit when possible.
- Return field-level errors in a stable shape.
- Keep database constraints for critical uniqueness.
- Avoid exposing sensitive validation details.
Validation designs that fail
- Trusting HTML
requiredas security. - Showing one generic error for every field.
- Validating differently on client and server.
- Forgetting async checks like email uniqueness.
- Letting disabled buttons replace real validation.
Describe the trust boundary
Use a concrete sentence:
I used this pattern because [problem]. The main tradeoff was [tradeoff]. I verified it by [test or check].
That structure works because it shows judgment. Anyone can name a tool. Strong developers explain why they chose it, what could go wrong, and how they checked the result.
Related API guides
- zod validation api boundaries typescript
- api error response format nodejs
- server actions vs api routes nextjs
Standards and references
One rule for both layers
Client validation improves user experience. Server validation protects the system. Keep the implementation small, verify the edge cases, and write the decision down so the next person can trust it.
Prove that server validation cannot be bypassed
The fastest useful test is not another browser click. Send the request directly with curl, Postman, or an integration test and omit the client entirely. Change a disabled field, send a negative amount, repeat a supposedly unique username, and include an unexpected property. The server should reject each invalid state with a stable error code.
For a money-moving workflow such as CryptoEx, the browser may warn that an amount exceeds the displayed balance. The server must still load the authoritative balance and reserve funds inside a database transaction. A stale tab, modified JavaScript, or direct HTTP client can bypass every React check.
const input = withdrawalSchema.parse(req.body);
await db.transaction(async (tx) => {
const account = await tx.account.lockForUpdate(input.accountId);
if (account.available < input.amount) {
throw new DomainError('INSUFFICIENT_FUNDS');
}
await tx.withdrawal.create(input);
await tx.account.reserve(input.amount);
});
The schema protects shape and basic ranges. The transaction protects a business invariant that depends on current state. Those are different jobs.
Keep messages useful without leaking internals
Return field-level feedback for expected input mistakes, but do not send database errors, stack traces, or raw policy rules to the browser. Log the internal cause with a request ID and return a stable public code. This gives the UI something reliable to render without turning an error response into a debugging dump for an attacker.
Questions for a validation review
Can a direct HTTP client bypass the browser rule? Does the server validate current state inside the same transaction that changes it? Are unknown fields rejected or ignored deliberately? Do public errors help the user without exposing internal policy or database details?
Finally, test accessibility. Error text should be connected to the field, announced to assistive technology, and preserved long enough to act on. Client validation is user interface work; server validation is enforcement. A good form needs both.
Discussion
What would you try, change, or challenge after reading this guide? Specific results and errors help the next reader.
Comments will load as you reach this section.