TypeBox — Schemas as TypeScript

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.

4 min read Level 3/5 #fastify#typebox#typescript
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.

Tuning Ajv →