ajv vs json-schema-to-ts
Runtime Validation vs TypeScript Type Generation from JSON Schema
ajvjson-schema-to-tsSimilar Packages:

Runtime Validation vs TypeScript Type Generation from JSON Schema

ajv and json-schema-to-ts both work with JSON Schema but serve fundamentally different purposes in the frontend development workflow. ajv is a high-performance runtime validator that checks if JavaScript objects conform to a given JSON Schema, throwing errors or returning boolean results at execution time. json-schema-to-ts, on the other hand, is a build-time tool that converts JSON Schema definitions into accurate TypeScript types, enabling static type checking during development without any runtime overhead. While they can be used together, they solve distinct problems: one ensures data correctness when your app runs, the other ensures type safety while you write code.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
ajv014,6151.03 MB31710 days agoMIT
json-schema-to-ts01,751122 kB24a year agoMIT

ajv vs json-schema-to-ts: Runtime Safety vs Compile-Time Types

Both ajv and json-schema-to-ts help developers work with JSON Schema in TypeScript projects, but they operate at completely different stages of the development lifecycle and solve different problems. Confusing them is common โ€” one validates data while your app runs, the other generates types while you write code. Letโ€™s clarify when and how to use each.

๐Ÿ” Core Purpose: What Problem Does Each Solve?

ajv is a runtime validator. It takes a JSON Schema and an actual JavaScript object, then checks whether the object matches the schema. If not, it tells you why โ€” useful for handling real-world data that might not match expectations.

import Ajv from 'ajv';

const ajv = new Ajv();
const schema = {
  type: 'object',
  properties: { name: { type: 'string' }, age: { type: 'number' } },
  required: ['name']
};

const validate = ajv.compile(schema);
const valid = validate({ name: 'Alice', age: 30 });
console.log(valid); // true

const invalid = validate({ age: 'thirty' });
console.log(invalid); // false
console.log(validate.errors); // detailed error info

json-schema-to-ts is a type generator. It reads a JSON Schema (usually as a const assertion in TypeScript) and produces a corresponding TypeScript type. No validation happens at runtime โ€” itโ€™s purely for static analysis during development.

import { FromSchema } from 'json-schema-to-ts';

const userSchema = {
  type: 'object',
  properties: { name: { type: 'string' }, age: { type: 'number' } },
  required: ['name']
} as const;

type User = FromSchema<typeof userSchema>;
// User is now equivalent to: { name: string; age?: number }

// This gives a TypeScript error at compile time:
const badUser: User = { age: 'thirty' }; // โŒ Property 'name' is missing

โš™๏ธ When to Use Which? Real Engineering Scenarios

Scenario 1: Validating API Responses from a Third-Party Service

Youโ€™re calling an external REST API that returns user data. You donโ€™t control the response format, and it might change unexpectedly.

  • โœ… Use ajv: Because you need to verify the shape of incoming data at runtime before using it in your app. TypeScript types alone wonโ€™t protect you if the server sends malformed JSON.
// Runtime check with ajv
if (!validate(response)) {
  throw new Error(`Invalid API response: ${ajv.errorsText(validate.errors)}`);
}
// Safe to use response.name, etc.
  • โŒ Donโ€™t rely only on json-schema-to-ts: Even if you generate a User type, the actual response might not match it. Youโ€™d get no runtime protection.

Scenario 2: Building an Internal Microservice with Schema-First Design

Your team defines all data contracts using JSON Schema files. Frontend and backend share these schemas, and you want TypeScript interfaces auto-generated from them.

  • โœ… Use json-schema-to-ts: To avoid manually writing and maintaining duplicate TypeScript interfaces. Changes to the schema automatically update your types.
// Shared schema โ†’ auto-generated type
const apiResponseSchema = { /* ... */ } as const;
type ApiResponse = FromSchema<typeof apiResponseSchema>;
  • โœ… Also consider ajv: If you still want to validate data at service boundaries (e.g., validating requests entering your backend), use both tools together.

๐Ÿ”„ Can They Be Used Together?

Yes โ€” and often should be. A common pattern in professional apps:

  1. Use json-schema-to-ts to generate TypeScript types from your canonical JSON Schemas.
  2. Use ajv to validate actual runtime data against those same schemas.

This gives you both compile-time type safety and runtime validation.

import Ajv from 'ajv';
import { FromSchema } from 'json-schema-to-ts';

const userSchema = {
  type: 'object',
  properties: { id: { type: 'number' }, email: { type: 'string', format: 'email' } },
  required: ['id', 'email']
} as const;

type User = FromSchema<typeof userSchema>;

// Compile-time: TypeScript enforces correct structure
const newUser: User = { id: 1, email: 'test@example.com' };

// Runtime: ajv validates actual data (e.g., from fetch)
const ajv = new Ajv({ strict: false });
const validate = ajv.compile(userSchema);

fetch('/api/user')
  .then(res => res.json())
  .then(data => {
    if (!validate(data)) {
      console.error('Invalid user data:', validate.errors);
      return;
    }
    // Now safe to treat `data` as User
    processUser(data);
  });

๐Ÿงช Error Handling and Developer Experience

ajv provides detailed, customizable error messages. You can even add your own keywords or formats (like format: 'uuid'). This is critical for debugging production issues or giving users meaningful form feedback.

// Custom format support in ajv
ajv.addFormat('uuid', /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i);

json-schema-to-ts has no runtime behavior, so thereโ€™s nothing to โ€œhandleโ€ at runtime. Its DX benefit is catching mismatches before you run the code. For example, if you forget a required field, TypeScript fails the build.

๐Ÿ“ฆ Bundle Impact and Performance

  • ajv adds to your bundle size because it includes a full validation engine. However, it supports tree-shaking and standalone code generation to minimize this.
  • json-schema-to-ts adds zero runtime cost. The entire package is dev-only; its output is pure TypeScript types that vanish after compilation.

If youโ€™re building a lightweight frontend where every KB counts and you fully trust your data sources, json-schema-to-ts alone may suffice. But if you handle untrusted input (user forms, third-party APIs), skipping runtime validation is risky.

๐Ÿ›‘ Maintenance Status

As of the latest official documentation:

  • ajv is actively maintained, with stable support for JSON Schema Draft 7, 2019-09, and 2020-12 via plugins.
  • json-schema-to-ts is also actively maintained and compatible with modern TypeScript versions. It correctly handles complex schema constructs like oneOf, anyOf, and recursive references.

Neither package is deprecated.

๐Ÿ’ก Final Guidance

  • Need to check real data while your app runs? โ†’ ajv
  • Want TypeScript types that match your schema without manual upkeep? โ†’ json-schema-to-ts
  • Working on a serious application with external data sources? โ†’ Use both

Donโ€™t treat them as competitors โ€” theyโ€™re complementary tools in a mature frontend architecture. One guards your runtime, the other sharpens your development experience.

How to Choose: ajv vs json-schema-to-ts

  • ajv:

    Choose ajv when you need to validate dynamic or external data (like API responses, user input, or config files) at runtime to prevent invalid data from breaking your application. Itโ€™s essential for enforcing contracts where type safety alone isnโ€™t enough โ€” for example, when consuming third-party APIs or handling form submissions. Its extensive support for JSON Schema Draft 7 and newer, plus powerful features like custom keywords and error reporting, makes it the go-to for robust validation logic.

  • json-schema-to-ts:

    Choose json-schema-to-ts when your team maintains JSON Schemas as the source of truth for data structures and wants those schemas to automatically generate precise TypeScript interfaces. This eliminates manual type duplication and ensures your TypeScript code stays in sync with your schema definitions. Itโ€™s ideal for internal APIs or systems where schema-first design is practiced, and you want compile-time guarantees without runtime performance costs.

README for ajv

Ajv logo

ย 

Ajv JSON schema validator

The fastest JSON validator for Node.js and browser.

Supports JSON Schema draft-04/06/07/2019-09/2020-12 (draft-04 support requires ajv-draft-04 package) and JSON Type Definition RFC8927.

build npm npm downloads Coverage Status SimpleX Gitter GitHub Sponsors

Ajv sponsors

Mozilla

Microsoft

RetoolTideliftSimpleX

Contributing

More than 100 people contributed to Ajv, and we would love to have you join the development. We welcome implementing new features that will benefit many users and ideas to improve our documentation.

Please review Contributing guidelines and Code components.

Documentation

All documentation is available on the Ajv website.

Some useful site links:

Please sponsor Ajv development

Since I asked to support Ajv development 40 people and 6 organizations contributed via GitHub and OpenCollective - this support helped receiving the MOSS grant!

Your continuing support is very important - the funds will be used to develop and maintain Ajv once the next major version is released.

Please sponsor Ajv via:

Thank you.

Open Collective sponsors

Performance

Ajv generates code to turn JSON Schemas into super-fast validation functions that are efficient for v8 optimization.

Currently Ajv is the fastest and the most standard compliant validator according to these benchmarks:

Performance of different validators by json-schema-benchmark:

performance

Features

Install

To install version 8:

npm install ajv

Getting started

Try it in the Node.js REPL: https://runkit.com/npm/ajv

In JavaScript:

// or ESM/TypeScript import
import Ajv from "ajv"
// Node.js require:
const Ajv = require("ajv")

const ajv = new Ajv() // options can be passed, e.g. {allErrors: true}

const schema = {
  type: "object",
  properties: {
    foo: {type: "integer"},
    bar: {type: "string"},
  },
  required: ["foo"],
  additionalProperties: false,
}

const data = {
  foo: 1,
  bar: "abc",
}

const validate = ajv.compile(schema)
const valid = validate(data)
if (!valid) console.log(validate.errors)

Learn how to use Ajv and see more examples in the Guide: getting started

Changes history

See https://github.com/ajv-validator/ajv/releases

Please note: Changes in version 8.0.0

Version 7.0.0

Version 6.0.0.

Code of conduct

Please review and follow the Code of conduct.

Please report any unacceptable behaviour to ajv.validator@gmail.com - it will be reviewed by the project team.

Security contact

To report a security vulnerability, please use the Tidelift security contact. Tidelift will coordinate the fix and disclosure. Please do NOT report security vulnerabilities via GitHub issues.

Open-source software support

Ajv is a part of Tidelift subscription - it provides a centralised support to open-source software users, in addition to the support provided by software maintainers.

License

MIT