# typebox: JSON Schema built as a TypeScript value

> A TypeScript library where the schema object is the type, and the static type is inferred from it. Nearly 7,000 stars, no published releases, and a repository set up for Deno tasks while the README only documents npm.

**sinclairzx81/typebox** — JSON Schema Type Builder with Static Type Resolution for TypeScript

- Repository: https://github.com/sinclairzx81/typebox
- Website: https://sinclairzx81.github.io/typebox/
- Stars: 6,989 · Forks: 217
- Language: TypeScript
- License: NOASSERTION
- Published: 2026-10-08 · Updated: 2026-10-08 · Language: en
- Canonical page: https://hysenlabs.com/projects/sinclairzx81-typebox

## One value, two consumers

The core idea is small enough to state in a sentence and unusual enough to be worth understanding properly. Instead of defining a TypeScript interface and separately writing a validator, you construct a schema value with a builder function, and the TypeScript type is inferred from that value.

Installing it is one package:

```bash
$ npm install typebox
```

The first example in the README shows the whole mechanism. You call Type.Object with a map of property builders, assign the result to a const, and then use Type.Static on that const to obtain the TypeScript type:

```typescript
import Type from 'typebox'

const T = Type.Object({                     // const T = {
  x: Type.Number(),                         //   type: 'object',
  y: Type.Number(),                         //   required: ['x', 'y', 'z']
  z: Type.Number()                          //   properties: {
})                                          //     x: { type: 'number' },
                                            //     y: { type: 'number' },
                                            //     z: { type: 'number' }
                                            //   },
                                            // }
```

The comments on the right are not decoration. They show the plain JSON Schema that the object literal produces, which is the actual runtime value of T. The last part of the example, type T = Type.Static<typeof T>, is what turns that value into the static type { x: number, y: number, z: number }.

So the schema is not a description that sits beside your types. It is a value, and the type is derived from the value. That direction of derivation is what removes the drift you normally get when an interface and a validator describe the same shape and quietly stop agreeing.

## Composition is the point

The README describes the library as a runtime type system that creates in-memory JSON Schema objects, and it goes further: the schematics are designed to match the static type checking rules of the TypeScript compiler, so JSON Schema is meant to compose the way TypeScript types compose.

That claim is what makes the library more than a validator wrapper. If composition genuinely follows the compiler's rules, you can build a schema out of reusable pieces and compose those pieces the way you would compose function signatures. A field validated as an email address carries the format through to the emitted schema:

```typescript
import Type from 'typebox'

const User = Type.Object({
  id: Type.String(),
  name: Type.String(),
  email: Type.String({ format: 'email' })
})
```

The corresponding schema declares id, name and email in required and maps the third property to a string with an email format. The inferred static type is the same three fields as strings. Nothing in that example is unusual, which is the point: the ordinary case reads like ordinary code.

Because the result is a plain in-memory JSON Schema object, it can be handed to any compliant validator. There is no proprietary validation step in the pipeline, and no requirement that validation and typing share a runtime. That property matters most at the boundary where you have already committed to a schema standard, such as an API contract that other teams consume, or a persisted document format that has to outlive the code that wrote it. The README names REST and RPC services as the intended integration points for exactly this reason.

The design also has a consequence worth stating plainly. Since the type comes from the value rather than the other way round, the inferred types are limited to what JSON Schema can express. Constructs that exist only in TypeScript, such as unions of function types or class private fields, have no schema representation, and the schema vocabulary is the ceiling on what you can infer.

## Type.Script parses TypeScript at the type level

The second capability the README documents is Type.Script, described as a micro TypeScript engine that transforms TypeScript definitions into JSON Schema. The engine operates inside the type system, and the README lists the programmable constructs it supports as including Conditional, Mapped, Indexed, Generics and Distributive Generics.

This is the feature that separates the library from a straightforward schema builder, and it is also the one with the least guidance attached to it. The README example begins by declaring vector types inside a template string, and the README excerpt stops partway through that block. What the shown portion establishes is that the input is TypeScript source written as text, and that the transformation is performed by the library itself rather than by a separate compiler step.

Two things follow. First, the cost profile differs from the builder API. Constructing Type.Object calls happen at runtime and are cheap. Type.Script parsing happens in the type checker, and the more TypeScript you ask it to parse, the more work the compiler does on every build. Conditional and distributive generic constructs are precisely the patterns that make a type checker slow, so the engine's capability and its cost are the same axis.

Second, syntax support is a moving target rather than a settled contract. Syntax highlighting for these definitions is shipped as a separate Visual Studio Marketplace extension published by the same author, which tells you the embedded source is a distinct language surface with its own tooling. When you adopt it, pin the package version and expect the parse surface to move with it.

The practical advice is to start with the builder API and treat Type.Script as something you adopt for a specific need, not as the default way to write schemas.

## No releases, so changelog/ is the version record

The repository publishes no GitHub releases. For a package with 6,965 stars, 213 forks and commits landing as recently as September 2026, that is a meaningful gap in how the project is presented, and it has a direct effect on how you should consume it.

What the repository root does contain is a changelog/ directory, alongside design/, docs/, example/, src/, task/ and test/ directories. So the version history exists, it just lives in the tree rather than in a releases feed. That means there is no release page to link to in a dependency review, no tag list to diff against, and no release notes to skim before an upgrade. The changelog directory and your lockfile are the two references that actually pin down what you are running.

The README's own table of contents lists four sections beyond the type material: Type, Script, Schema, and then Versions and Contribute. The presence of a Versions section is consistent with a project that expects readers to track releases through its own documentation rather than through GitHub.

Two further repository details affect day to day work. The root carries deno.jsonc, deno.lock, tasks.ts and a task/ directory, which together describe a Deno-driven development setup using Deno's own task runner, while the README's only install instruction is the npm line shown earlier. Both facts are current, and they are not in conflict, but the practical reading is that the Deno configuration serves the project's internal build and task workflow. Nothing in the README presents Deno as a supported way for consumers to install the package.

The examples directory is where the runtime story gets concrete. Its listing includes example/index.ts plus legacy/, mcp/, prototype/, scripting/ and standard/ subdirectories. A scripting/ directory lines up with Type.Script, an mcp/ directory suggests an example built around tool schemas, and a legacy/ directory is the kind of thing that exists to keep older usage compiling while the current API moves. Those directories are the fastest way to see which usage shape the project currently considers current.

## Licensing and metadata that need a second look

GitHub reports the license for this repository as unclassified, while the README carries a badge claiming MIT and the repository root contains a file named license. Three signals, and they do not line up.

The likely explanation is mundane. Automated license detection generally expects a file named LICENSE or COPYING in a recognised format, and it inspects the first lines for a known license text. A file named license in lowercase can be enough to defeat that check on a case-sensitive lookup, which is why a project with an unambiguous MIT badge can still show as unclassified in the API. The repository is not license-free, and the README is not lying about MIT. What is missing is the metadata that tools read.

Why this matters in practice: package scanners, license compliance checks and automated dependency audits read the metadata field, not the README badge. If your organisation gates on that field, this repository will need a manual exception or you will need to verify the file contents yourself and record the result. Reading the license file is the correct move, and it costs a minute.

The open issue count deserves a similar note. The repository shows zero open issues alongside nearly 7,000 stars, which is unusual enough that it is worth understanding rather than reading as a health signal. A project at this scale either keeps its tracker exceptionally clean, or routes discussion elsewhere, such as the Discord or discussion venues the README links, or has issues disabled on the repository. The README does link to external community venues, so the tracker is plausibly a secondary channel rather than the primary one.

The description field, JSON Schema Type Builder with Static Type Resolution for TypeScript, is a fair summary of what the library does. The topic list is narrower, carrying only jsonschema and typescript, which understates a library that also presents a type-level script engine.

## Where this fits against the alternatives

TypeBox occupies a specific position among TypeScript schema libraries, and the honest way to describe it is by what it emits rather than by how it feels to write.

The output is plain JSON Schema. That is the whole contract. Any validator that accepts JSON Schema can consume a TypeBox value, and any consumer of your published contract can read it without knowing anything about TypeScript. If you publish schemas for other teams or other languages, this is the property that matters, and it is the reason to accept a slightly less ergonomic authoring style.

What you give up for that neutrality is the ability to express types JSON Schema has no vocabulary for, and any static inference is bounded by the schema vocabulary as a result. If your data shapes are mostly records, arrays, strings, numbers and their compositions, which is most API and configuration data, the ceiling is not something you will hit.

The other axis is where validation happens. A schema builder that carries its own validator gives you a parse function alongside the schema. Emitting a standard schema means you choose the validator, which is a feature when you already have one or when you need a specific implementation for a runtime you care about. It is a decision to make deliberately rather than by default.

Type.Script sits outside that comparison. A type-level engine that parses TypeScript source is not something the builder-plus-standard-output approach attempts at all, and if you need to derive a schema from existing type definitions rather than the reverse, that is the feature to evaluate the library on.

The repository's own structure reinforces the practical recommendation. With docs/, an examples directory organised by usage pattern and a design/ directory in the root, the documentation is substantial and worth reading before you commit, particularly the docs section linked from the README, which is where the API surface beyond the four-line quickstart will be.

## Conclusion

TypeBox is worth reaching for when one schema has to do two jobs, because the object you build is simultaneously the JSON Schema and the source of the static TypeScript type, with no second declaration to keep in sync. The practical cautions are specific. The package publishes no GitHub releases, so changelog/ in the repository is the only version history and your lockfile is the only thing pinning what you have. The repository root carries deno.jsonc, deno.lock, tasks.ts and a task/ directory for Deno-driven development, while the README documents a single npm install line, so treat the Deno setup as an internal workflow rather than a supported entry point until the documentation says otherwise. And the license field reads as unclassified next to a file named license and a README badge claiming MIT, so read that file yourself before this matters to you. If you only validate at the boundaries of a service, a validator without a schema type layer keeps the dependency smaller. If your schemas are shared between a TypeScript client and a server, or published as an API contract, the single-source property here is the reason to adopt it.

## FAQ

### What is a TypeBox?

TypeBox is a TypeScript library for building JSON Schema objects. You construct a schema value with functions like Type.Object, and Type.Static derives the matching TypeScript type from that value, so one declaration serves both runtime validation and static typing.

### How do I install typebox?

The README documents a single npm command, npm install typebox. The repository root also carries deno.jsonc, deno.lock and tasks.ts for the project's own Deno-based development workflow, but the README does not present Deno as a supported install path for consumers.

### Where do I find the version history for typebox?

The repository publishes no GitHub releases. Version history is kept in the changelog/ directory in the repository root, so the changelog and your lockfile are the two references that pin down which version you have.

### Can I use a TypeBox schema with any JSON Schema validator?

Yes. TypeBox produces in-memory JSON Schema objects rather than a proprietary format, so the value can be handed to any compliant validator. The trade-off is that you select and configure the validator yourself rather than receiving a parse function from the schema library.

### What license is typebox under?

The README badge claims MIT and the repository root contains a file named license, but GitHub reports the license field as unclassified, most likely because the file name does not match what automated detection looks for. Read the license file in the repository to confirm the terms before relying on the metadata.

## Sources

- [Issues](https://github.com/sinclairzx81/typebox/issues)
- [Project website](https://sinclairzx81.github.io/typebox/)
- [README](https://github.com/sinclairzx81/typebox/blob/main/README.md)
- [sinclairzx81/typebox on GitHub](https://github.com/sinclairzx81/typebox)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/sinclairzx81-typebox
