Define Once, Get JSON Schema + TS Types
TypeBox — Schemas as TypeScript
TypeBox lets you express JSON Schema with TypeScript syntax, then derive both a Schema and static types from a single definition.
What you'll learn
- Install @sinclair/typebox and the type provider
- Define schemas with Type.Object and friends
- Use withTypeProvider for fully typed routes
Writing JSON Schema by hand is fine; keeping it in sync with TypeScript types is not. TypeBox solves both — define a schema in TS and get both the runtime schema and the static type.
Install
npm i @sinclair/typebox @fastify/type-provider-typebox Define a Schema
import { Type, type Static } from '@sinclair/typebox';
export const UserBody = Type.Object({
email: Type.String({ format: 'email' }),
password: Type.String({ minLength: 8 }),
name: Type.Optional(Type.String()),
});
export type UserBody = Static<typeof UserBody>;
// { email: string; password: string; name?: string } UserBody works at runtime as a JSON Schema and at compile time as a TS type.
Wire It Into a Route
import Fastify from 'fastify';
import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox';
const app = Fastify().withTypeProvider<TypeBoxTypeProvider>();
app.post('/users', {
schema: { body: UserBody },
handler: async (req) => {
// req.body.email is `string`, req.body.name is `string | undefined`
return createUser(req.body);
},
}); No generics on app.post, no duplicate types. If you tighten the schema (maxLength: 64 on
name), both runtime validation and the TypeScript type update together.
Compose and Reuse
TypeBox primitives (Type.Array, Type.Union, Type.Pick, Type.Omit) make schema composition
feel like normal TS. Pull shared shapes into a schemas/ folder and import them across routes.