Zod on the server and the client: the schema you define once and the three ways it breaks in runtime

80% of Next.js projects using Zod have the same schema imported from three different contexts. And only one of those three contexts behaves exactly the way Zod promises.

Yeah, you read that right. The mental model of "define the schema once and validate everywhere" is true inside the library — but in a real stack with Next.js 16 — Server Actions, edge middleware, and API routes — you're dealing with three execution environments with different constraints, and Zod doesn't always arrive complete to all three.

My thesis: Zod is one of the best tools in the TypeScript ecosystem, but sharing the same schema across client, Node.js server, and edge runtime without thinking about context differences produces three specific failure classes that aren't obvious until they blow up. This post documents those three failures and the pattern that prevents them.

The problem nobody draws in the diagram