TypeScript promises that if your code compiles without errors, your types are sound. But the second data leaves the server and crosses the network boundary as JSON, that compile-time promise vanishes. A single missed optional property or misspelled key can crash a client component in production.
Many teams react by writing duplicate type definitions: an interface on the server, a DTO validator class, an OpenAPI schema, and a TypeScript type on the frontend. The result is hundreds of lines of synchronization boilerplate that inevitably drifts over time.
Validating at the system boundary
Runtime type validation must happen precisely at the boundary where external data enters your system. In our architecture, incoming HTTP payloads, webhook requests, and third-party API responses pass through strict Zod schemas before any application handler executes.
Using a custom NestJS validation pipe powered by Zod, requests with invalid shapes are rejected with structured 422 Unprocessable Entity responses before reaching business logic. Inside the controller, the data is guaranteed to match the inferred TypeScript type.
Single source of truth for contracts
Rather than manually copying types between apps/api and apps/web, our monorepo exports shared contracts from packages/contracts. We define the schema once using Zod, and infer the static TypeScript type directly using z.infer.
import { z } from 'zod';
export const CreateProjectSchema = z.object({
title: z.string().min(3).max(80),
slug: z.string().regex(/^[a-z0-9-]+$/),
category: z.enum(['Architecture', 'Backend', 'Frontend', 'Database']),
featured: z.boolean().default(false),
});
export type CreateProjectDto = z.infer<typeof CreateProjectSchema>;Catching API drift at build time
In a full-stack codebase, contract drift is caught in CI before any code can be merged. By running TypeScript typechecks (tsc --noEmit) across the entire pnpm workspace simultaneously, any breaking change in an API signature lights up red in pull request checks.
This eliminates defensive runtime checks on the frontend. You can write clean, confident React Server Components knowing the data contract is mathematically verified end-to-end.
