End-to-End Type Safety

One set of types flowing from database to API to UI, so renaming a column breaks the build instead of breaking production.

shared types between frontend and backendit yells at me before it breakstypos caught before deploytypes all the way throughthe API and the frontend agree on typesno more guessing what the API returnsend to end typesafetytypesafe api

See it

Live demo coming soon

What it is

One definition of each shape, inferred across every boundary: database row, API input and output, client response, form values. Nobody hand-writes a second interface that describes what the endpoint 'probably' returns. The usual cast: Prisma or Drizzle generating row types from the database schema, Zod schemas describing what shows up at an untrusted runtime boundary, and tRPC (or typed server actions, or GraphQL codegen) carrying the router's types straight into the client. Note that those are two different sources of truth: the database owns what you store, the schemas own what arrives from outside. Do not try to make one generate the other.

The payoff is where the error appears. Rename a column and the build goes red in the editor, listing the six call sites, instead of a user hitting undefined in production on a Saturday. It pays best in one TypeScript repo or monorepo; across teams or languages you get a generated client from OpenAPI instead, which is the same idea with more ceremony.

Gotcha: types evaporate at runtime. A typed fetch response is a promise, not a guarantee, so parse everything untrusted (request bodies, third-party JSON, form data, process.env) with a runtime schema and derive the TypeScript type from that schema rather than the reverse. And one 'as' cast or stray any in the middle of the chain turns the whole thing decorative while still looking green.

Ask AI for it

Wire end-to-end type safety through this stack using the ORM and the API mechanism already in this repository. Do not introduce a second ORM or swap the transport. Keep the database schema authoritative for persistence types and use the types its client already generates. Separately, define Zod schemas for every untrusted boundary (request bodies, form data, third-party responses, process.env) and derive the TypeScript types from those schemas with z.infer rather than writing them by hand. Have the API layer take its input and output types from those two sources, and let the client infer the contract from the API definition instead of re-declaring a response interface. Enable strict mode in tsconfig, remove every 'any' and every 'as' cast that crosses a boundary, and add a blocking typecheck step to CI so a renamed field fails the build.

You might have meant

data fetchingserver actionprops vs statemonorepo