## File: README.md

&nbsp;

# 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](https://ajv.js.org/json-schema.html#draft-04) requires ajv-draft-04 package) and JSON Type Definition [RFC8927](https://datatracker.ietf.org/doc/rfc8927/).

[](https://github.com/ajv-validator/ajv/actions?query=workflow%3Abuild)
[](https://www.npmjs.com/package/ajv)
[](https://www.npmjs.com/package/ajv)
[](https://coveralls.io/github/ajv-validator/ajv?branch=master)
[](https://simplex.chat/contact#/?v=1-2&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2F8KvvURM6J38Gdq9dCuPswMOkMny0xCOJ%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAr8rPVRuMOXv6kwF2yUAap-eoVg-9ssOFCi1fIrxTUw0%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%224pwLRgWHU9tlroMWHz0uOg%3D%3D%22%7D)
[](https://gitter.im/ajv-validator/ajv)
[](https://github.com/sponsors/epoberezkin)

## Ajv sponsors

[](https://www.mozilla.org)[](https://opencollective.com/ajv)

[](https://opensource.microsoft.com)[](https://opencollective.com/ajv)[](https://opencollective.com/ajv)

[](https://retool.com/?utm_source=sponsor&utm_campaign=ajv)[](https://tidelift.com/subscription/pkg/npm-ajv?utm_source=npm-ajv&utm_medium=referral&utm_campaign=enterprise)[](https://github.com/simplex-chat/simplex-chat)[](https://opencollective.com/ajv)

## 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](./CONTRIBUTING.md) and [Code components](https://ajv.js.org/components.html).

## Documentation

All documentation is available on the [Ajv website](https://ajv.js.org).

Some useful site links:

- [Getting started](https://ajv.js.org/guide/getting-started.html)
- [JSON Schema vs JSON Type Definition](https://ajv.js.org/guide/schema-language.html)
- [API reference](https://ajv.js.org/api.html)
- [Strict mode](https://ajv.js.org/strict-mode.html)
- [Standalone validation code](https://ajv.js.org/standalone.html)
- [Security considerations](https://ajv.js.org/security.html)
- [Command line interface](https://ajv.js.org/packages/ajv-cli.html)
- [Frequently Asked Questions](https://ajv.js.org/faq.html)

## <a name="sponsors"></a>Please [sponsor Ajv development](https://github.com/sponsors/epoberezkin)

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:

- [GitHub sponsors page](https://github.com/sponsors/epoberezkin) (GitHub will match it)
- [Ajv Open Collective](https://opencollective.com/ajv)

Thank you.

#### Open Collective sponsors

[](https://opencollective.com/ajv)

[](https://opencollective.com/ajv/organization/0/website)
[](https://opencollective.com/ajv/organization/1/website)
[](https://opencollective.com/ajv/organization/2/website)
[](https://opencollective.com/ajv/organization/3/website)
[](https://opencollective.com/ajv/organization/4/website)
[](https://opencollective.com/ajv/organization/5/website)
[](https://opencollective.com/ajv/organization/6/website)
[](https://opencollective.com/ajv/organization/7/website)
[](https://opencollective.com/ajv/organization/8/website)
[](https://opencollective.com/ajv/organization/9/website)
[](https://opencollective.com/ajv/organization/10/website)
[](https://opencollective.com/ajv/organization/11/website)
[](https://opencollective.com/ajv/organization/12/website)
[](https://opencollective.com/ajv/organization/13/website)
[](https://opencollective.com/ajv/organization/14/website)
[](https://opencollective.com/ajv/organization/15/website)
[](https://opencollective.com/ajv/organization/16/website)
[](https://opencollective.com/ajv/organization/17/website)
[](https://opencollective.com/ajv/organization/18/website)
[](https://opencollective.com/ajv/organization/19/website)
[](https://opencollective.com/ajv/organization/20/website)
[](https://opencollective.com/ajv/organization/21/website)
[](https://opencollective.com/ajv/organization/22/website)
[](https://opencollective.com/ajv/organization/23/website)
[](https://opencollective.com/ajv/organization/24/website)

## 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:

- [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark) - 50% faster than the second place
- [jsck benchmark](https://github.com/pandastrike/jsck#benchmarks) - 20-190% faster
- [z-schema benchmark](https://rawgit.com/zaggino/z-schema/master/benchmark/results.html)
- [themis benchmark](https://cdn.rawgit.com/playlyfe/themis/master/benchmark/results.html)

Performance of different validators by [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark):

[](https://github.com/ebdrup/json-schema-benchmark/blob/master/README.md#performance)

## Features

- Ajv implements JSON Schema [draft-06/07/2019-09/2020-12](http://json-schema.org/) standards (draft-04 is supported in v6):
  - all validation keywords (see [JSON Schema validation keywords](https://ajv.js.org/json-schema.html))
  - [OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.3.md) extensions:
    - NEW: keyword [discriminator](https://ajv.js.org/json-schema.html#discriminator).
    - keyword [nullable](https://ajv.js.org/json-schema.html#nullable).
  - full support of remote references (remote schemas have to be added with `addSchema` or compiled to be available)
  - support of recursive references between schemas
  - correct string lengths for strings with unicode pairs
  - JSON Schema [formats](https://ajv.js.org/guide/formats.html) (with [ajv-formats](https://github.com/ajv-validator/ajv-formats) plugin).
  - [validates schemas against meta-schema](https://ajv.js.org/api.html#api-validateschema)
- NEW: supports [JSON Type Definition](https://datatracker.ietf.org/doc/rfc8927/):
  - all keywords (see [JSON Type Definition schema forms](https://ajv.js.org/json-type-definition.html))
  - meta-schema for JTD schemas
  - "union" keyword and user-defined keywords (can be used inside "metadata" member of the schema)
- supports [browsers](https://ajv.js.org/guide/environments.html#browsers) and Node.js 18.x - current
- [asynchronous loading](https://ajv.js.org/guide/managing-schemas.html#asynchronous-schema-loading) of referenced schemas during compilation
- "All errors" validation mode with [option allErrors](https://ajv.js.org/options.html#allerrors)
- [error messages with parameters](https://ajv.js.org/api.html#validation-errors) describing error reasons to allow error message generation
- i18n error messages support with [ajv-i18n](https://github.com/ajv-validator/ajv-i18n) package
- [removing-additional-properties](https://ajv.js.org/guide/modifying-data.html#removing-additional-properties)
- [assigning defaults](https://ajv.js.org/guide/modifying-data.html#assigning-defaults) to missing properties and items
- [coercing data](https://ajv.js.org/guide/modifying-data.html#coercing-data-types) to the types specified in `type` keywords
- [user-defined keywords](https://ajv.js.org/guide/user-keywords.html)
- additional extension keywords with [ajv-keywords](https://github.com/ajv-validator/ajv-keywords) package
- [\$data reference](https://ajv.js.org/guide/combining-schemas.html#data-reference) to use values from the validated data as values for the schema keywords
- [asynchronous validation](https://ajv.js.org/guide/async-validation.html) of user-defined formats and keywords

## Install

To install version 8:

```
npm install ajv
```

## <a name="usage"></a>Getting started

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

In JavaScript:

```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](https://ajv.js.org/guide/getting-started.html)

## Changes history

See [https://github.com/ajv-validator/ajv/releases](https://github.com/ajv-validator/ajv/releases)

**Please note**: [Changes in version 8.0.0](https://github.com/ajv-validator/ajv/releases/tag/v8.0.0)

[Version 7.0.0](https://github.com/ajv-validator/ajv/releases/tag/v7.0.0)

[Version 6.0.0](https://github.com/ajv-validator/ajv/releases/tag/v6.0.0).

## Code of conduct

Please review and follow the [Code of conduct](./CODE_OF_CONDUCT.md).

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](https://tidelift.com/security).
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](https://tidelift.com/subscription/pkg/npm-ajv?utm_source=npm-ajv&utm_medium=referral&utm_campaign=readme) - it provides a centralised support to open-source software users, in addition to the support provided by software maintainers.

## License

[MIT](./LICENSE)

---

## File: docs/guide/async-validation.md

# Asynchronous validation

You can define formats and keywords that perform validation asynchronously by accessing database or some other service. You should add `async: true` in the keyword or format definition (see [addFormat](./api.md#api-addformat), [addKeyword](./api.md#api-addkeyword) and [User-defined keywords](./keywords.md)).

If your schema uses asynchronous formats/keywords or refers to some schema that contains them it should have `"$async": true` keyword so that Ajv can compile it correctly. If asynchronous format/keyword or reference to asynchronous schema is used in the schema without `$async` keyword Ajv will throw an exception during schema compilation.

::: warning Use $async: true in referenced schemas
All asynchronous subschemas that are referenced from the current or other schemas should have `"$async": true` keyword as well, otherwise the schema compilation will fail.
:::

Validation function for an asynchronous format/keyword should return a promise that resolves with `true` or `false` (or rejects with `new Ajv.ValidationError(errors)` if you want to return errors from the keyword function).

Ajv compiles asynchronous schemas to [async functions](http://tc39.github.io/ecmascript-asyncawait/). Async functions are supported in Node.js 7+ and all modern browsers. You can supply a transpiler as a function via `processCode` option. See [Options](./api.md#options).

The compiled validation function has `$async: true` property (if the schema is asynchronous), so you can differentiate these functions if you are using both synchronous and asynchronous schemas.

Validation result will be a promise that resolves with validated data or rejects with an exception `Ajv.ValidationError` that contains the array of validation errors in `errors` property.

Example:

```javascript
const ajv = new Ajv()

ajv.addKeyword({
  keyword: "idExists",
  async: true,
  type: "number",
  validate: checkIdExists,
})

async function checkIdExists(schema, data) {
  // this is just an example, you would want to avoid SQL injection in your code
  const rows = await sql(`SELECT id FROM ${schema.table} WHERE id = ${data}`)
  return !!rows.length // true if record is found
}

const schema = {
  $async: true,
  properties: {
    userId: {
      type: "integer",
      idExists: {table: "users"},
    },
    postId: {
      type: "integer",
      idExists: {table: "posts"},
    },
  },
}

const validate = ajv.compile(schema)

validate({userId: 1, postId: 19})
  .then(function (data) {
    console.log("Data is valid", data) // { userId: 1, postId: 19 }
  })
  .catch(function (err) {
    if (!(err instanceof Ajv.ValidationError)) throw err
    // data is invalid
    console.log("Validation errors:", err.errors)
  })
```

### Using transpilers

```javascript
const ajv = new Ajv({processCode: transpileFunc})
const validate = ajv.compile(schema) // transpiled es7 async function
validate(data).then(successFunc).catch(errorFunc)
```

See [Options](../options).

---

## File: docs/guide/combining-schemas.md

# Combining schemas

[[toc]]

## <a name="ref"></a>Combining schemas with $ref

You can structure your validation logic across multiple schema files and have schemas reference each other using `$ref` keyword.

Example:

```javascript
const schema = {
  $id: "http://example.com/schemas/schema.json",
  type: "object",
  properties: {
    foo: {$ref: "defs.json#/definitions/int"},
    bar: {$ref: "defs.json#/definitions/str"},
  },
}

const defsSchema = {
  $id: "http://example.com/schemas/defs.json",
  definitions: {
    int: {type: "integer"},
    str: {type: "string"},
  },
}
```

Now to compile your schema you can either pass all schemas to Ajv instance:

```javascript
const ajv = new Ajv({schemas: [schema, defsSchema]})
const validate = ajv.getSchema("http://example.com/schemas/schema.json")
```

or use `addSchema` method:

```javascript
const ajv = new Ajv()
const validate = ajv.addSchema(defsSchema).compile(schema)
```

See [Options](../options.md) and [addSchema](../api.md#add-schema) method.

::: tip Reference resolution
- `$ref` is resolved as the uri-reference using schema \$id as the base URI (see the example).
- References can be recursive (and mutually recursive) to implement the schemas for different data structures (such as linked lists, trees, graphs, etc.).
- You don't have to host your schema files at the URIs that you use as schema \$id. These URIs are only used to identify the schemas, and according to JSON Schema specification validators should not expect to be able to download the schemas from these URIs.
- The actual location of the schema file in the file system is not used.
- You can pass the identifier of the schema as the second parameter of `addSchema` method or as a property name in `schemas` option. This identifier can be used instead of (or in addition to) schema \$id.
- You cannot have the same \$id (or the schema identifier) used for more than one schema - the exception will be thrown.
- You can implement dynamic resolution of the referenced schemas using `compileAsync` method. In this way you can store schemas in any system (files, web, database, etc.) and reference them without explicitly adding to Ajv instance. See [Asynchronous schema compilation](./managing-schemas.md#asynchronous-schema-compilation).
:::

## Extending recursive schemas

While statically defined `$ref` keyword allows to split schemas to multiple files, it is difficult to extend recursive schemas - the recursive reference(s) in the original schema points to the original schema, and not to the extended one. So in JSON Schema draft-07 the only available solution to extend the recursive schema was to redefine all sections of the original schema that have recursion.

It was particularly repetitive when extending meta-schema, as it has many recursive references, but even in a schema with a single recursive reference extending it was very verbose.

JSON Schema draft-2019-09 and the upcoming draft defined the mechanism for dynamic recursion using keywords `$recursiveRef`/`$recursiveAnchor` (draft-2019-09) or `$dynamicRef`/`$dynamicAnchor` (the next JSON Schema draft) that is somewhat similar to "open recursion" in functional programming.

Consider this recursive schema with static recursion:

```javascript
const treeSchema = {
  $id: "https://example.com/tree",
  type: "object",
  required: ["data"],
  properties: {
    data: true,
    children: {
      type: "array",
      items: {$ref: "#"},
    },
  },
}
```

The only way to extend this schema to prohibit additional properties is by adding `additionalProperties` keyword right in the schema - this approach can be impossible if you do not control the source of the original schema. Ajv also provided the additional keywords in [ajv-merge-patch](https://github.com/ajv-validator/ajv-merge-patch) package to extend schemas by treating them as plain JSON data. While this approach may work for you, it is non-standard and therefore not portable.

The new keywords for dynamic recursive references allow extending this schema without modifying it:

```javascript
const treeSchema = {
  $id: "https://example.com/tree",
  $recursiveAnchor: true,
  type: "object",
  required: ["data"],
  properties: {
    data: true,
    children: {
      type: "array",
      items: {$recursiveRef: "#"},
    },
  },
}

const strictTreeSchema = {
  $id: "https://example.com/strict-tree",
  $recursiveAnchor: true,
  $ref: "tree",
  unevaluatedProperties: false,
}

import Ajv2019 from "ajv/dist/2019"
// const Ajv2019 = require("ajv/dist/2019")
const ajv = new Ajv2019({
  schemas: [treeSchema, strictTreeSchema],
})
const validate = ajv.getSchema("https://example.com/strict-tree")
```

See [dynamic-refs](https://github.com/ajv-validator/ajv/blob/master/spec/dynamic-ref.spec.ts) test for the example using `$dynamicAnchor`/`$dynamicRef`.

At the moment Ajv implements the spec for dynamic recursive references with these limitations:

- `$recursiveAnchor`/`$dynamicAnchor` can only be used in the schema root.
- `$recursiveRef`/`$dynamicRef` can only be hash fragments, without URI.

Ajv also does not support dynamic references in [asynchronous schemas](#asynchronous-validation) (Ajv extension) - it is assumed that the referenced schema is synchronous, and there is no validation-time check for it.

## $data reference

With `$data` option you can use values from the validated data as the values for the schema keywords. See [proposal](https://github.com/json-schema-org/json-schema-spec/issues/51) for more information about how it works.

`$data` reference is supported in the keywords: const, enum, format, maximum/minimum, exclusiveMaximum / exclusiveMinimum, maxLength / minLength, maxItems / minItems, maxProperties / minProperties, formatMaximum / formatMinimum, formatExclusiveMaximum / formatExclusiveMinimum, multipleOf, pattern, required, uniqueItems.

The value of "$data" should be a [JSON-pointer](https://datatracker.ietf.org/doc/rfc6901/) to the data (the root is always the top level data object, even if the $data reference is inside a referenced subschema) or a [relative JSON-pointer](http://tools.ietf.org/html/draft-luff-relative-json-pointer-00) (it is relative to the current point in data; if the \$data reference is inside a referenced subschema it cannot point to the data outside of the root level for this subschema).

Examples.

This schema requires that the value in property `smaller` is less or equal than the value in the property larger:

```javascript
const ajv = new Ajv({$data: true})

const schema = {
  properties: {
    smaller: {
      type: "number",
      maximum: {$data: "1/larger"},
    },
    larger: {type: "number"},
  },
}

const validData = {
  smaller: 5,
  larger: 7,
}

ajv.validate(schema, validData) // true
```

This schema requires that the properties have the same format as their field names:

```javascript
const schema = {
  additionalProperties: {
    type: "string",
    format: {$data: "0#"},
  },
}

const validData = {
  "date-time": "1963-06-19T08:30:06.283185Z",
  email: "joe.bloggs@example.com",
}
```

`$data` reference is resolved safely - it won't throw even if some property is undefined. If `$data` resolves to `undefined` the validation succeeds (with the exclusion of `const` keyword). If `$data` resolves to incorrect type (e.g. not "number" for maximum keyword) the validation fails.

## $merge and $patch keywords

With the package [ajv-merge-patch](https://github.com/ajv-validator/ajv-merge-patch) you can use the keywords `$merge` and `$patch` that allow extending JSON Schemas with patches using formats [JSON Merge Patch (RFC 7396)](https://datatracker.ietf.org/doc/rfc7396/) and [JSON Patch (RFC 6902)](https://datatracker.ietf.org/doc/rfc6902/).

To add keywords `$merge` and `$patch` to Ajv instance use this code:

```javascript
require("ajv-merge-patch")(ajv)
```

Examples.

Using `$merge`:

```javascript
{
  $merge: {
    source: {
      type: "object",
      properties: {p: {type: "string"}},
      additionalProperties: false
    },
    with: {
      properties: {q: {type: "number"}}
    }
  }
}
```

Using `$patch`:

```javascript
{
  $patch: {
    source: {
      type: "object",
      properties: {p: {type: "string"}},
      additionalProperties: false
    },
    with: [{op: "add", path: "/properties/q", value: {type: "number"}}]
  }
}
```

The schemas above are equivalent to this schema:

```javascript
{
  type: "object",
  properties: {
    p: {type: "string"},
    q: {type: "number"}
  },
  additionalProperties: false
}
```

The properties `source` and `with` in the keywords `$merge` and `$patch` can use absolute or relative `$ref` to point to other schemas previously added to the Ajv instance or to the fragments of the current schema.

See the package [ajv-merge-patch](https://github.com/ajv-validator/ajv-merge-patch) for more information.

---

## File: docs/guide/environments.md

# Execution environments

[[toc]]

## Server-side Node.js

The main consideration for using Ajv server-side is to [manage compiled schemas](./managing-schemas) correctly, ensuring that the same schema is not compiled more than once.

## Short-lived environments

Depending on the life-time of the environments, the benefits from "compile once - validate many times" model can be limited - you can consider using [standalone validation code](../standalone).

If you have a pre-defined set of schemas, you can:

1. compile all schemas in the build step - you can either write your own script or use [ajv-cli](https://github.com/ajv-validator/ajv).
2. generate and beautify standalone validation code - you can have all your schemas exported from one file.
3. additionally, you can inline all dependencies on Ajv or ajv-formats using any bundling tools.
4. deploy compiled schemas as part of your application or library (with or without dependency on Ajv, depending on whether you did step 3 and which validation keywords are used in the schemas)

Please see [gajus/table](https://github.com/gajus/table) package that pre-compiles schemas in this way.

Even if your schemas need to be stored in the database, you can still compile schemas once and store your validation functions alongside schemas in the database as well, loading them on demand.

## Browsers

See [Content Security Policy](../security.md#content-security-policy) to decide how best to use Ajv in the browser for your use case.

Whether you compile schemas in the browser or use [standalone validation code](../standalone), it is recommended that you bundle them together with your application code.

If you need to use Ajv in several application bundles you can create a separate UMD bundles of Ajv using `npm run bundle` script.

In this case you need to load Ajv using the correct bundle, depending on which schema language and which version you need to use:

<code-group>
<code-block title="JSON Schema (draft-07)">
```html
<script src="bundle/ajv7.min.js"></script>
<script>
  ;(function () {
    const Ajv = window.ajv7
    const ajv = new Ajv()
  })()
</script>
```
</code-block>

<code-block title="JSON Schema (draft-2019-09)">
```html
<script src="bundle/ajv2019.min.js"></script>
<script>
  ;(function () {
    const Ajv = window.ajv2019
    const ajv = new Ajv()
  })()
</script>
```
</code-block>

<code-block title="JSON Type Definition">
```html
<script src="bundle/ajvJTD.min.js"></script>
<script>
  ;(function () {
    const Ajv = window.ajvJTD
    const ajv = new Ajv()
  })()
</script>
```
</code-block>
</code-group>

This bundle can be used with different module systems; it creates global `ajv`/`ajv2019`/`ajvJTD` if no module system is found.

The browser bundles are available on [cdnjs](https://cdnjs.com/libraries/ajv).

::: warning Some frameworks re-define require
Some frameworks, e.g. Dojo, may redefine global require in a way that is not compatible with CommonJS module format. In this case Ajv bundle has to be loaded before the framework and then you can use global `ajv` (see issue [#234](https://github.com/ajv-validator/ajv/issues/234)).
:::

::: warning Internet Explorer 11
Ajv v8 in IE 11 will not work straight out of the box. To use it either [recompile it](../standalone.md), or set the options [unicodeRegExp](../options.md#unicoderegexp) to `false` and `code: { es5: true }`, and transpile the Ajv node module (see issue [#1585](https://github.com/ajv-validator/ajv/issues/1585#issuecomment-832486204)).
:::

## ES5 environments

You need to:

- recompile Typescript to ES5 target - it is set to 2018 in the bundled compiled code.
- generate ES5 validation code:

```javascript
const ajv = new Ajv({code: {es5: true}})
```

See [Advanced options](https://github.com/ajv-validator/ajv/blob/master/docs/api.md#advanced-options).

## CJS vs ESM exports

The default configuration of AJV is to generate code in ES6 with Common JS (CJS) exports. This can be changed by setting 
the ES Modules(ESM) flag.

```javascript
const ajv = new Ajv({code: {esm: true}})
```

## Other JavaScript environments

Ajv is used in other JavaScript environments, including Electron apps, WeChat mini-apps and many others, where the same considerations apply as above:

- compilation performance
- restrictive content security policy
- bundle size

If any of this is important, you may have better results with pre-compiled [standalone validation code](../standalone).

## Command line interface

Ajv can be used from the terminal in any operating system supported by Node.js

CLI is available as a separate npm package [ajv-cli](https://github.com/ajv-validator/ajv-cli).

It supports:

- compiling JSON Schemas to test their validity
- generating [standalone validation code](./docs/standalone.md) that exports validation function(s)
- migrating schemas to draft-07 and draft-2019-09 (using [json-schema-migrate](https://github.com/epoberezkin/json-schema-migrate))
- validating data file(s) against JSON Schema
- testing expected validity of data against JSON Schema
- referenced schemas
- user-defined meta-schemas, validation keywords and formats
- files in JSON, JSON5, YAML, and JavaScript format
- all Ajv options
- reporting changes in data after validation in [JSON-patch](https://datatracker.ietf.org/doc/rfc6902/) format

---

## File: docs/guide/formats.md

# Format validation

## String formats

From version 7 Ajv does not include formats defined by JSON Schema specification - these and several other formats are provided by [ajv-formats](https://github.com/ajv-validator/ajv-formats) plugin.

To add all formats from this plugin:

<code-group>
<code-block title="JavaScript">
```javascript
const Ajv = require("ajv")
const addFormats = require("ajv-formats")

const ajv = new Ajv()
addFormats(ajv)
```
</code-block>

<code-block title="TypeScript">
```typescript
import Ajv from "ajv"
import addFormats from "ajv-formats"

const ajv = new Ajv()
addFormats(ajv)
```
</code-block>
</code-group>

See [ajv-formats](https://github.com/ajv-validator/ajv-formats) documentation for further details.

It is recommended NOT to use "format" keyword implementations with untrusted data, as they may use potentially unsafe regular expressions (even though known issues are fixed) - see [ReDoS attack](../security.md#redos-attack).

::: danger Format validation of untrusted data
If you need to use "format" keyword to validate untrusted data, you MUST assess their suitability and safety for your validation scenarios.
:::

The following formats are defined in [ajv-formats](https://github.com/ajv-validator/ajv-formats) for string validation with "format" keyword:

- _date_: full-date according to [RFC3339](http://tools.ietf.org/html/rfc3339#section-5.6).
- _time_: time with optional time-zone.
- _date-time_: date-time from the same source (time-zone is mandatory).
- _duration_: duration from [RFC3339](https://tools.ietf.org/html/rfc3339#appendix-A)
- _uri_: full URI.
- _uri-reference_: URI reference, including full and relative URIs.
- _uri-template_: URI template according to [RFC6570](https://datatracker.ietf.org/doc/rfc6570/)
- _url_ (deprecated): [URL record](https://url.spec.whatwg.org/#concept-url).
- _email_: email address.
- _hostname_: host name according to [RFC1034](http://tools.ietf.org/html/rfc1034#section-3.5).
- _ipv4_: IP address v4.
- _ipv6_: IP address v6.
- _regex_: tests whether a string is a valid regular expression by passing it to RegExp constructor.
- _uuid_: Universally Unique Identifier according to [RFC4122](https://datatracker.ietf.org/doc/rfc4122/).
- _json-pointer_: JSON-pointer according to [RFC6901](https://datatracker.ietf.org/doc/rfc6901/).
- _relative-json-pointer_: relative JSON-pointer according to [this draft](http://tools.ietf.org/html/draft-luff-relative-json-pointer-00).

::: warning Additional formats in ajv-formats-draft2019
JSON Schema draft-07 also defines formats `iri`, `iri-reference`, `idn-hostname` and `idn-email` for URLs, hostnames and emails with international characters. These formats are available in [ajv-formats-draft2019](https://github.com/luzlab/ajv-formats-draft2019) plugin.
:::

## User-defined formats

You can add and replace any formats using [addFormat](../api.md#ajv-addformat-name-string-format-format-ajv) method:

```javascript
ajv.addFormat("identifier", /^a-z\$_[a-zA-Z$_0-9]*$/)
```

Ajv also allows defining the formats that would be applied to numbers only:

```javascript
ajv.addFormat("byte", {
  type: "number",
  validate: (x) => x >= 0 && x <= 255 && x % 1 == 0,
})
```

## Formats and standalone validation code

If you use formats from [ajv-formats](https://github.com/ajv-validator/ajv-formats) package, [standalone validation code](../standalone) will be supported out of the box.

::: warning Standalone code and Ajv versions
You need to make sure that ajv-formats imports the same version and the same code of ajv as the one you use in your application for standalone validation code to work (because of `instanceof` check that is currently used).

`npm` and other package managers may not update the version of ajv dependency of ajv-formats when you update version of ajv in your application - the workaround is to use clean npm installation.
:::

If you define your own formats, for standalone code generation to work you need to pass the code snippet that evaluates to an object with all defined formats to the option `code.formats`:

<code-group>
<code-block title="JavaScript">
```javascript
const {default: Ajv, _} = require("ajv")
const ajv = new Ajv({code: {formats: _`require("./my_formats")`}})
```
</code-block>

<code-block title="TypeScript">
```typescript
import Ajv, {_} from "ajv"
const ajv = new Ajv({code: {formats: _`require("./my_formats")`}})
```
</code-block>
</code-group>

---

## File: docs/guide/getting-started.md

# Getting started

[[toc]]

## Install

::: tip Node REPL
You can try Ajv without installing it in the Node.js REPL: [https://runkit.com/npm/ajv](https://runkit.com/npm/ajv)
:::

To install Ajv version 8:

```bash
npm install ajv
```

If you need to use Ajv with [JSON Schema draft-04](./schema-language#draft-04), you need to install Ajv version 6:

```bash
npm install ajv@6
```

See [Contributing](../CONTRIBUTING.md) on how to run the tests locally

## Basic data validation

Ajv takes a schema for your JSON data and converts it into a very efficient JavaScript code
that validates your data according to the schema. To create a schema you can use either
[JSON Schema](../json-schema) or [JSON Type Definition](../json-type-definition) - check out [Choosing schema language](./schema-language), they have
different advantages and disadvantages.

For example, to validate an object that has a required property "foo" (an integer number), an optional property "bar" (a string) and no other properties:

<code-group>
<code-block title="JSON Schema">
```javascript
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 validate = ajv.compile(schema)

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

const valid = validate(data)
if (!valid) console.log(validate.errors)
```
</code-block>

<code-block title="JSON Type Definition">
```javascript
const Ajv = require("ajv/dist/jtd")
const ajv = new Ajv() // options can be passed, e.g. {allErrors: true}

const schema = {
  properties: {
    foo: {type: "int32"}
  },
  optionalProperties: {
    bar: {type: "string"}
  }
}


const validate = ajv.compile(schema)

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

const valid = validate(data)
if (!valid) console.log(validate.errors)
```
</code-block>
</code-group>

Ajv compiles schemas to functions and caches them in all cases (using the schema itself as a key in a Map), so that the next time the same schema object is used it won't be compiled again.

::: tip Best performance: compile and getSchema methods
The best performance is achieved when using compiled functions returned by `compile` or `getSchema` methods.

While execution of the compiled validation function is very fast, its compilation is
relatively slow, so you need to make sure that you compile schemas only once and
re-use compiled validation functions. See [Managing multiple schemas](./managing-schemas).
:::

::: warning Save errors property
Every time a validation function (or `ajv.validate`) is called the `errors` property is overwritten. You need to copy the `errors` array reference to another variable if you want to use it later (e.g. in the callback). See [Validation errors](../api.md#validation-errors).
:::

## Parsing and serializing JSON 

Ajv can compile efficient parsers and serializers from [JSON Type Definition](../json-type-definition) schemas.

Serializing the data with a function specialized to your data shape can be more than 10x compared with `JSON.stringify`.

Parsing the data replaces the need for separate validation after generic parsing with `JSON.parse` (although validation itself is usually much faster than parsing). In case your JSON string is valid, the specialized parsing is approximately as fast as JSON.parse, but in case your JSON is invalid, the specialized parsing would fail much faster - so it can be very efficient in some scenarios.

For the same data structure, you can compile parser and serializer in this way:

<code-group>
<code-block title="JSON Type Definition">
```javascript
const Ajv = require("ajv/dist/jtd")
const ajv = new Ajv() // options can be passed, e.g. {allErrors: true}

const schema = {
  properties: {
    foo: {type: "int32"}
  },
  optionalProperties: {
    bar: {type: "string"}
  }
}

const serialize = ajv.compileSerializer(schema)

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

console.log(serialize(data))

const parse = ajv.compileParser(schema)

const json = '{"foo": 1, "bar": "abc"}'
const invalidJson = '{"unknown": "abc"}'

parseAndLog(json) // logs {foo: 1, bar: "abc"}
parseAndLog(invalidJson) // logs error and position

function parseAndLog(json) {
  const data = parse(json)
  if (data === undefined) {
    console.log(parse.message) // error message from the last parse call
    console.log(parse.position) // error position in string
  } else {
    console.log(data)
  }
}
```
</code-block>
</code-group>

::: tip Lower parsing performance of empty schemas
You would have smaller performance benefits in case your schema contains some properties or other parts that are empty schemas (`{}`) - parser would call `JSON.parse` in this case.
:::

::: warning JTD discriminator schema
The performance of parsing discriminator schemas depends on the position of discriminator tag in the schema - the best parsing performance will be achieved if the tag is the first property - this is how compiled JTD serializers generate JSON in case of discriminator schemas.

Also, if discriminator tag were to be repeated in JSON, the second value would be ignored and the object still validated according to the first tag.
:::

::: warning Compiled parsers do NOT throw exceptions
Compiled parsers, unlike JSON.parse, do not throw the exception in case JSON string is not a valid JSON or in case data is invalid according to the schema. As soon as the parser determines that either JSON or data is invalid, it returns `undefined` and reports error and position via parsers properties `message` and `position`.
:::

---

## File: docs/guide/managing-schemas.md

# Managing schemas

[[toc]]

## Re-using validation functions

Ajv validation model is optimized for server side execution, when schema compilation happens only once and validation happens multiple times - this has a substantial performance benefit comparing with validators that interpret the schema in the process of validation.

Transition from template-based code generation in Ajv v6 to the tree-based in v7 brought:

- type-level safety against code injection via untrusted schemas
- more efficient validation code (via [tree optimizations](../codegen.md#code-optimization))
- smaller memory footprint of compiled functions (schemas are no longer serialized)
- smaller bundle size
- more maintainable code

These improvements cost slower schema compilation, and increased chance of re-compilation in case you pass a different schema object (see [#1413](https://github.com/ajv-validator/ajv/issues/1413)), so it is very important to manage schemas correctly, so they are only compiled once.

There are several approaches to manage compiled schemas.

## Standalone validation code

The motivation to pre-compile schemas:

- faster startup times
- lower memory footprint/bundle size
- compatible with strict content security policies
- almost no risk to compile schema more than once
- better for short-lived environments

See [Standalone validation code](../standalone) for the details.

There are scenarios when it can be not possible or difficult:

- dynamic or user-provided schemas - while you can do caching, it can be either difficult to implement or inefficient.
- user-defined keywords that use closures that are difficult to serialize as code.

## Compiling during initialization

The simplest approach is to compile all your schemas when the application starts, outside of the code that handles requests. It can be done simply in the module scope:

<code-group>
<code-block title="JavaScript">
```javascript
const Ajv = require("ajv").default
const schema_user = require("./schema_user.json")
const ajv = new Ajv()
const validate_user = ajv.compile(schema_user)





// this is just some abstract API framework
app.post("/user", async (cxt) => {
  if (validate_user(cxt.body)) {
    // create user
  } else {
    // report error
    cxt.status(400)
  }
})
```
</code-block>

<code-block title="TypeScript">
```javascript
import Ajv from "ajv"
import * as schema_user from "./schema_user.json"
const ajv = new Ajv()
const validate_user = ajv.compile(schema_user)

interface User {
  username: string
}

// this is just some abstract API framework
app.post("/user", async (cxt) => {
  if (validate_user(cxt.body)) {
    // create user
  } else {
    // report error
    cxt.status(400)
  }
})
```
</code-block>
</code-group>

::: warning Use single Ajv instance
It is recommended to use a single Ajv instance for the whole application, so if you use validation in more than one module, you should:

- require Ajv in a separate module responsible for validation
- compile all validators there
- export them to be used in multiple modules of your application
:::

## Using Ajv instance cache

Another, more effective approach, is to use Ajv instance cache to have all compiled validators available anywhere in your application from a single import.

In this case you would have a separate module where you instantiate Ajv and use this instance in your application.

You can load all schemas and add them to Ajv instance in a single `validation` module:

<code-group>
<code-block title="validation.js">
```javascript
const Ajv = require("ajv")
const schema_user = require("./schema_user.json")
const schema_document = require("./schema_document.json")
const ajv = exports.ajv = new Ajv()
ajv.addSchema(schema_user, "user")
ajv.addSchema(schema_document, "document")
```
</code-block>

<code-block title="validation.ts">
```typescript
import Ajv from "ajv"
import * as schema_user from "./schema_user.json"
import * as schema_document from "./schema_document.json"
export const ajv = new Ajv()
ajv.addSchema(schema_user, "user")
ajv.addSchema(schema_document, "document")
```
</code-block>
</code-group>

And then you can import Ajv instance and access any schema in any application module, for example `user` module:

<code-group>
<code-block title="user.js">
```javascript
const {ajv} = require("./validation")





// this is just some abstract API framework
app.post("/user", async (cxt) => {
  const validate = ajv.getSchema("user")
  if (validate(cxt.body)) {
    // create user
  } else {
    // report error
    cxt.status(400)
  }
})
```
</code-block>

<code-block title="users.ts">
```javascript
import ajv from "./validation"

interface User {
  username: string
}

// this is just some abstract API framework
app.post("/user", async (cxt) => {
  const validate = ajv.getSchema("user")
  if (validate(cxt.body)) {
    // create user
  } else {
    // report error
    cxt.status(400)
  }
})
```
</code-block>
</code-group>

::: tip On-demand vs preliminary compilation
In the example above, schema compilation happens only once, on the first API call, not at the application start-up time. It means that the application would start a bit faster, but the first API call would be a bit slower. If this is undesirable, you could, for example, call `getSchema` for all added schemas after they are added, then when `getSchema` is called inside route handler it would simply get compiled validation function from the instance cache.
:::

### Cache key: schema vs key vs $id

In the example above, the key passed to the `addSchema` method was used to retrieve schemas from the cache. Other options are:

- use schema root $id attribute. While it usually looks like URI, it does not mean Ajv downloads it from this URI - this is simply $id used to identify and access the schema. You can though configure Ajv to download schemas on demand - see [Asynchronous schema loading](#asynchronous-schema-loading)
- use schema object itself as a key to the cache (it is possible, because Ajv uses Map). This approach is not recommended, because it would only work if you pass the same instance of the schema object that was passed to `addSchema` method - it is easy to make a mistake that would result in schema being compiled every time it is used.

### Pre-adding all schemas vs adding on demand

In the example above all schemas were added in advance. It is also possible, to add schemas as they are used - it can be helpful if there are many schemas. In this case, you need to check first whether the schema is already added by calling `getSchema` method - it would return `undefined` if not:

```javascript
const schema_user = require("./schema_user.json")
let validate = ajv.getSchema("user")
if (!validate) {
  ajv.addSchema(schema_user, "user")
  validate = ajv.getSchema("user")
}
```

If your schema has `$id` attribute, for example:

<code-group>
<code-block title="schema_user.json">
```json
{
  "$id": "https://example.com/user.json",
  "type": "object",
  "properties": {
    "username": {"type": "string"}
  },
  required: ["username"]
}
```
</code-block>
</code-group>

then the above logic can be simpler:

```javascript
const schema_user = require("./schema_user.json")
const validate = ajv.getSchema("https://example.com/user.json")
              || ajv.compile(schema_user)
```

The above is possible because when the schema has `$id` attribute `compile` method both compiles the schema (returning the validation function) and adds it to the Ajv instance cache at the same time.

### Asynchronous schema loading

There are cases when you need to have a large collection of schemas stored in some database or on the remote server. In this case you are likely to use schema `$id` as some resource identifier to retrieve it - either network URI or database ID.

You can use `compileAsync` [method](./api.md#api-compileAsync) to asynchronously load the schemas as they are compiled, loading the schemas that are referenced from compiled schemas on demand. Ajv itself does not do any IO operations, it uses the function you supply via `loadSchema` [option](./api.md#options) to load schema from the passed ID. This function should return `Promise` that resolves to the schema (you can use async function, as in the example).

Example:

```javascript
const ajv = new Ajv({loadSchema: loadSchema})

ajv.compileAsync(schema).then(function (validate) {
  const valid = validate(data)
  // ...
})

async function loadSchema(uri) {
  const res = await request.json(uri)
  if (res.statusCode >= 400) throw new Error("Loading error: " + res.statusCode)
  return res.body
}
```

## Caching schemas in your code

You can maintain cache of compiled schemas in your application independently from Ajv. It can be helpful in cases when you have multiple Ajv instances because, for example:

- you need to compile different schemas with different options
- you use both JSON Schema and JSON Type Definition schemas in one application
- you have $id conflicts between different third party schemas you do not control

Whatever approach you use, you need to ensure that each schema is compiled only once.

---

## File: docs/guide/modifying-data.md

# Modifying data during validation

[[toc]]

## General considerations

Ajv has several options that allow to modify data during validation:

- removeAdditional - to remove properties not defined in the schema object.
- useDefaults - to assign defaults from the schema to the validated data properties.
- coerceTypes - to change data type, when possible, to match the type(s) in the schema.

You can also define keywords that modify data.

::: tip NOT possible to modify root data
It is not possible to modify the root data instance passed to the validation function, only data properties can be modified. This is related to how JavaScript passes parameters, and not a limitation of Ajv.
:::

::: warning Non-portable functionality
This functionality is non-standard - this is likely to be unsupported in other JSON Schema validator implementations.
:::

::: danger Unexpected results when modifying data
While pure schema validation produces the results independent of the keywords and subschema order, enabling any feature that may modify the data makes validation impure and its results are likely to depend on the order of evaluation of keywords and subschemas.

The order of evaluation of subschemas in keywords like `allOf` is always the same as the order of subschemas in the array.

On another hand, the order of evaluation of keywords, while consistent between validations and not dependent on how schema object is created, is neither documented nor guaranteed, so it can change in the future major versions (and, in rare cases, it can change in minor version - e.g. when there is bug that needs to be fixed).

It is strongly recommended to always put user-defined keywords that can mutate data in separate subschemas inside `allOf` keyword to make the order of evaluation unambiguous. The exceptions to this recommendation are pre-defined `default` and `type` keywords - they must remain in the same schema as other keywords.
:::

## Removing additional properties

With [option `removeAdditional`](./api.md#options) (added by [andyscott](https://github.com/andyscott)) you can filter data during the validation.

This option modifies original data.

Example:

```javascript
const ajv = new Ajv({removeAdditional: true})
const schema = {
  additionalProperties: false,
  properties: {
    foo: {type: "number"},
    bar: {
      additionalProperties: {type: "number"},
      properties: {
        baz: {type: "string"},
      },
    },
  },
}

const data = {
  foo: 0,
  additional1: 1, // will be removed; `additionalProperties` == false
  bar: {
    baz: "abc",
    additional2: 2, // will NOT be removed; `additionalProperties` != false
  },
}

const validate = ajv.compile(schema)

console.log(validate(data)) // true
console.log(data) // { "foo": 0, "bar": { "baz": "abc", "additional2": 2 }
```

If `removeAdditional` option in the example above were `"all"` then both `additional1` and `additional2` properties would have been removed.

If the option were `"failing"` then property `additional1` would have been removed regardless of its value and property `additional2` would have been removed only if its value were failing the schema in the inner `additionalProperties` (so in the example above it would have stayed because it passes the schema, but any non-number would have been removed).

::: warning Unexpected results when using removeAdditional with anyOf/oneOf
If you use `removeAdditional` option with `additionalProperties` keyword inside `anyOf`/`oneOf` keywords your validation can fail with this schema. To make it work as you expect, you have to use discriminated union with [discriminator](../json-schema.md#discriminator) keyword (requires `discriminator` option).
:::

For example, with this non-discriminated union you will have unexpected results:

```javascript
{
  type: "object",
  oneOf: [
    {
      properties: {
        foo: {type: "string"}
      },
      required: ["foo"],
      additionalProperties: false
    },
    {
      properties: {
        bar: {type: "integer"}
      },
      required: ["bar"],
      additionalProperties: false
    }
  ]
}
```

The intention of the schema above is to allow objects with either the string property "foo" or the integer property "bar", but not with both and not with any other properties.

With the option `removeAdditional: true` the validation will pass for the object `{ "foo": "abc"}` but will fail for the object `{"bar": 1}`. It happens because while the first subschema in `oneOf` is validated, the property `bar` is removed because it is an additional property according to the standard (because it is not included in `properties` keyword in the same schema).

While this behaviour is unexpected (issues [#129](https://github.com/ajv-validator/ajv/issues/129), [#134](https://github.com/ajv-validator/ajv/issues/134)), it is correct. To have the expected behaviour (both objects are allowed and additional properties are removed) the schema has to be refactored in this way:

```javascript
{
  type: "object",
  properties: {
    foo: {type: "string"},
    bar: {type: "integer"}
  },
  additionalProperties: false,
  oneOf: [{required: ["foo"]}, {required: ["bar"]}]
}
```

The schema above is also more efficient - it will compile into a faster function.

For discriminated unions you could schemas with [discriminator](../json-schema.md#discriminator) keyword (it requires `discriminator: true` option):

```javascript
{
  type: "object",
  discriminator: {propertyName: "tag"},
  required: ["tag"],
  oneOf: [
    {
      properties: {
        tag: {const: "foo"},
        foo: {type: "string"}
      },
      required: ["foo"],
      additionalProperties: false
    },
    {
      properties: {
        tag: {const: "bar"},
        bar: {type: "integer"}
      },
      required: ["bar"],
      additionalProperties: false
    }
  ]
}
```

With this schema, only one subschema in `oneOf` will be evaluated, so `removeAdditional` option will work as expected.

See [discriminator](../json-schema.md#discriminator) keyword.

## Assigning defaults

With [option `useDefaults`](./options.md#options) Ajv will assign values from `default` keyword in the schemas of `properties` and `items` (when it is the array of schemas) to the missing properties and items.

With the option value `"empty"` properties and items equal to `null` or `""` (empty string) will be considered missing and assigned defaults.

This option modifies original data.

::: warning Defaults are deep-cloned
The default value is inserted in the generated validation code as a literal, so the value inserted in the data will be the deep clone of the default in the schema.
:::

Example 1 (`default` in `properties`):

```javascript
const ajv = new Ajv({useDefaults: true})
const schema = {
  type: "object",
  properties: {
    foo: {type: "number"},
    bar: {type: "string", default: "baz"},
  },
  required: ["foo", "bar"],
}

const data = {foo: 1}

const validate = ajv.compile(schema)

console.log(validate(data)) // true
console.log(data) // { "foo": 1, "bar": "baz" }
```

Example 2 (`default` in `items`):

```javascript
const schema = {
  type: "array",
  items: [{type: "number"}, {type: "string", default: "foo"}],
}

const data = [1]

const validate = ajv.compile(schema)

console.log(validate(data)) // true
console.log(data) // [ 1, "foo" ]
```

With `useDefaults` option `default` keywords throws exception during schema compilation when used in:

- not in `properties` or `items` subschemas
- in schemas inside `anyOf`, `oneOf` and `not` (see [#42](https://github.com/ajv-validator/ajv/issues/42))
- in `if` schema
- in schemas generated by user-defined _macro_ keywords

The strict mode option can change the behaviour for these unsupported defaults (`strict: false` to ignore them, `"log"` to log a warning).

See [Strict mode](../strict-mode.md).

::: tip Default with discriminator keyword
Defaults will be assigned in schemas inside `oneOf` in case [discriminator](../json-schema.md#discriminator) keyword is used.
:::

## Coercing data types

When you are validating user inputs all your data properties are usually strings. The option `coerceTypes` allows you to have your data types coerced to the types specified in your schema `type` keywords, both to pass the validation and to use the correctly typed data afterwards.

This option modifies original data.

::: warning Type coercion with scalar values
If you pass a scalar value to the validating function its type will be coerced and it will pass the validation, but the value of the variable you pass won't be updated because scalars are passed by value.
:::

Example 1:

```javascript
const ajv = new Ajv({coerceTypes: true})
const schema = {
  type: "object",
  properties: {
    foo: {type: "number"},
    bar: {type: "boolean"},
  },
  required: ["foo", "bar"],
}

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

const validate = ajv.compile(schema)

console.log(validate(data)) // true
console.log(data) // { "foo": 1, "bar": false }
```

Example 2 (array coercions):

```javascript
const ajv = new Ajv({coerceTypes: "array"})
const schema = {
  properties: {
    foo: {type: "array", items: {type: "number"}},
    bar: {type: "boolean"},
  },
}

const data = {foo: "1", bar: ["false"]}

const validate = ajv.compile(schema)

console.log(validate(data)) // true
console.log(data) // { "foo": [1], "bar": false }
```

The coercion rules, as you can see from the example, are different from JavaScript both to validate user input as expected and to have the coercion reversible (to correctly validate cases where different types are defined in subschemas of "anyOf" and other compound keywords).

See [Type coercion rules](../coercion.md) for details.

---

## File: docs/guide/schema-language.md

---
tags:
  - JTD
---

# Choosing schema language

[[toc]]

## JSON Type Definition

Ajv supports the new specification focussed on defining cross-platform types of JSON messages/payloads - JSON Type Definition (JTD). See the informal reference of [JTD schema forms](../json-type-definition) and formal specification [RFC8927](https://datatracker.ietf.org/doc/rfc8927/).

## JSON Schema

Ajv supports most widely used drafts of JSON Schema specification. Please see the informal reference of available [JSON Schema validation keywords](../json-schema) and [specification drafts](https://json-schema.org/specification.html).

### draft-04

Draft-04 is not included in Ajv v7, because of some differences it has with the following drafts:

- different schema member for schema identifier (`id` in draft-04 instead of `$id`)
- different syntax of exclusiveMaximum/Minimum

You can still use draft-04 schemas with Ajv v6 - while this is no longer actively developed, any security related issues would still be supported at least until 30/06/2021.

To install v6:

```bash
npm install ajv@6
```

You can migrate schemas from draft-04 to draft-07 using [ajv-cli](https://github.com/ajv-validator/ajv-cli).

### draft-07 (and draft-06)

These are the most widely used versions of JSON Schema specification, and they are supported with the main ajv export.

```javascript
import Ajv from "ajv"
const ajv = new Ajv()
```

If you need to support draft-06 schemas you need to add additional meta-schema, but you may just change (or remove) `$schema` attribute in your schemas - no other changes are needed:

```javascript
const draft6MetaSchema = require("ajv/dist/refs/json-schema-draft-06.json")
ajv.addMetaSchema(draft6MetaSchema)
```

### draft 2019-09 (and draft-2020-12)

The main advantage of this JSON Schema version over draft-07 is the ability to spread the definition of records that do not allow additional properties across multiple schemas. If you do not need it, you might be better off with draft-07.

To use Ajv with the support of all JSON Schema draft-2019-09/2020-12 features you need to use a different export:

```javascript
import Ajv2019 from "ajv/dist/2019"
const ajv = new Ajv2019()
```

Optionally, you can add draft-07 meta-schema, to use both draft-07 and draft-2019-09 schemas in one Ajv instance:

```javascript
const draft7MetaSchema = require("ajv/dist/refs/json-schema-draft-07.json")
ajv.addMetaSchema(draft7MetaSchema)
```

Draft-2019-09 support is provided via a separate export in order to avoid increasing the bundle and generated code size for draft-07 users.

With this import Ajv supports the following features:

- keywords [`unevaluatedProperties`](../json-schema.md#unevaluatedproperties) and [`unevaluatedItems`](../json-schema.md#unevaluateditems)
- keywords [`dependentRequired`](../json-schema.md#dependentrequired), [`dependentSchemas`](../json-schema.md#dependentschemas), [`maxContains`/`minContains`](../json-schema.md#maxcontains-mincontains)
- dynamic recursive references with [`recursiveAnchor`/`recursiveReference`] - see [Extending recursive schemas](./combining-schemas.md#extending-recursive-schemas)
- draft-2019-09 meta-schema is the default.

::: warning Draft-2019-09 features performance cost (even when not used)
Supporting dynamic recursive references and `unevaluatedProperties`/`unevaluatedItems` keywords adds additional generated code even to the validation functions where these features are not used (when possible, Ajv determines which properties/items are "unevaluated" at compilation time, but support for dynamic references always adds additional generated code). If you are not using these features in your schemas it is recommended to use default Ajv export with JSON-Schema draft-07 support.
:::

## Comparison

Both [JSON Schema](../json-schema.md) and [JSON Type Definition](../json-type-definition.md) are cross-platform specifications with implementations in multiple programming languages that define the shape of your JSON data.

You can see the difference between the two specifications in [Getting started](./getting-started) section examples.

This section compares their pros/cons to help decide which specification fits your application better.

### JSON Schema

**Pros**:

- Wide specification adoption.
- Used as part of OpenAPI specification.
- Support of complex validation scenarios:
  - untagged unions and boolean logic
  - conditional schemas and dependencies
  - restrictions on the number ranges and the size of strings, arrays and objects
  - semantic validation with formats, patterns and content keywords
  - distribute strict record definitions across multiple schemas (with unevaluatedProperties)
- Can be effectively used for validation of any JavaScript objects and configuration files.

**Cons**:

- Defines the collection of restrictions on the data, rather than the shape of the data.
- No standard support for tagged unions.
- Complex and error prone for the new users (Ajv has [strict mode](../strict-mode) enabled by default to compensate for it, but it is not cross-platform).
- Some parts of specification are difficult to implement, creating the risk of implementations divergence:
  - reference resolution model
  - unevaluatedProperties/unevaluatedItems
  - dynamic recursive references
- Internet draft status (rather than RFC)

See [JSON Schema](../json-schema.md) for more information and the list of defined keywords.

### JSON Type Definition

**Pros**:

- Aligned with type systems of many languages - can be used to generate type definitions and efficient parsers and serializers to/from these types.
- Very simple, enforcing the best practices for cross-platform JSON API modelling.
- Simple to implement, ensuring consistency across implementations.
- Defines the shape of JSON data via strictly defined schema forms (rather than the collection of restrictions).
- Effective support for tagged unions.
- Designed to protect against user mistakes.
- Supports compilation of schemas to efficient [serializers and parsers](./getting-started.md#parsing-and-serializing-json) (no need to validate as a separate step).
- Approved as [RFC8927](https://datatracker.ietf.org/doc/rfc8927/).
- Substantial industry adoption since it was standardized in 2020, Ajv v8.12.0 fixed all reported JTD bugs.

**Cons**:

- Limited, compared with JSON Schema - no support for untagged unions<sup>1</sup>, conditionals, references between different schema files<sup>2</sup>, etc.
- No meta-schema in the specification<sup>3</sup>.

<sup>1</sup> Ajv defines non-standard keyword "union" that can be used inside "metadata" object.

<sup>2</sup> You can still combine schemas from multiple files in the application code.

<sup>3</sup> Ajv defines meta-schema for JTD schemas.

See [JSON Type Definition](../json-type-definition.md) for more information and the list of defined schema forms.

---

## File: docs/guide/typescript.md

# Using with TypeScript

[[toc]]

## Additional functionality

Ajv takes advantage of TypeScript type system to provide additional functionality that is not possible in JavaScript:

- utility types `JSONSchemaType` and `JTDSchemaType` to convert data type into the schema type to simplify writing schemas, both for [JSON Schema](../json-schema.md) (but without union support) and for [JSON Type Definition](../json-type-definition) (with tagged unions support).
- utility type `JTDDataType` to convert JSON Type Definition schema into the type of data that it defines.
- compiled validation functions are type guards that narrow the type after successful validation.
- validation errors for JSON Schema are defined as tagged unions, for type-safe error handling.
- when utility type is used, compiled JTD serializers only accept data of correct type (as they do not validate that the data is valid) and compiled parsers return correct data type.

## Utility types for schemas

For the same example as in [Getting started](./getting-started):
 - ensure strictNullChecks is true

<code-group>
<code-block title="JSON Schema">
```typescript
import Ajv, {JSONSchemaType} from "ajv"
const ajv = new Ajv()

interface MyData {
  foo: number
  bar?: string
}

const schema: JSONSchemaType<MyData> = {
  type: "object",
  properties: {
    foo: {type: "integer"},
    bar: {type: "string", nullable: true}
  },
  required: ["foo"],
  additionalProperties: false
}

// validate is a type guard for MyData - type is inferred from schema type
const validate = ajv.compile(schema)

// or, if you did not use type annotation for the schema,
// type parameter can be used to make it type guard:
// const validate = ajv.compile<MyData>(schema)

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

if (validate(data)) {
  // data is MyData here
  console.log(data.foo)
} else {
  console.log(validate.errors)
}
```
</code-block>

<code-block title="JSON Type Definition">
```typescript
import Ajv, {JTDSchemaType} from "ajv/dist/jtd"
const ajv = new Ajv()

interface MyData {
  foo: number
  bar?: string
}

const schema: JTDSchemaType<MyData> = {
  properties: {
    foo: {type: "int32"}
  },
  optionalProperties: {
    bar: {type: "string"}
  }
}


// validate is a type guard for MyData - type is inferred from schema type
const validate = ajv.compile(schema)

// or, if you did not use type annotation for the schema,
// type parameter can be used to make it type guard:
// const validate = ajv.compile<MyData>(schema)

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

if (validate(data)) {
  // data is MyData here
  console.log(data.foo)
} else {
  console.log(validate.errors)
}
```
</code-block>
</code-group>

See [this test](https://github.com/ajv-validator/ajv/tree/master/spec/types/json-schema.spec.ts) for an advanced example.

## Utility type for JTD data type

You can use JTD schema to construct the type of data using utility type `JTDDataType`

<code-group>
<code-block title="JSON Type Definition">
```typescript
import Ajv, {JTDDataType} from "ajv/dist/jtd"
const ajv = new Ajv()

const schema = {
  properties: {
    foo: {type: "int32"}
  },
  optionalProperties: {
    bar: {type: "string"}
  }
} as const

type MyData = JTDDataType<typeof schema>

// type inference is not supported for JTDDataType yet
const validate = ajv.compile<MyData>(schema)

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

if (validate(validData)) {
  // data is MyData here
  console.log(validData.foo)
} else {
  console.log(validate.errors)
}
```
</code-block>
</code-group>
 

::: warning TypeScript limitation
Note that it's currently not possible for `JTDDataType` to know whether the compiler is inferring timestamps as strings or Dates, and so it conservatively types any timestamp as `string | Date`. This is accurate, but often requires extra validation on the part of the user to confirm they're getting the appropriate data type.
:::

## Type-safe error handling

With both [JSON Schema](../json-schema.md) and [JSON Type Definition](../json-type-definition.md), the validation error type is an open union, but it can be cast to tagged unions (using validation keyword as tag) for easier error handling.

Continuing the example above:

<code-group>
<code-block title="JSON Schema">
```typescript
import {DefinedError} from "ajv"

// ...

if (validate(data)) {
  // data is MyData here
  console.log(data.foo)
} else {
  // The type cast is needed, as Ajv uses a wider type to allow extension
  // You can extend this type to include your error types as needed.
  for (const err of validate.errors as DefinedError[]) {
    switch (err.keyword) {
      case "type":
        // err type is narrowed here to have "type" error params properties
        console.log(err.params.type)
      break
        // ...
    }
  }
}
```
</code-block>

<code-block title="JSON Type Definition">
```typescript
import {JTDErrorObject} from "ajv/dist/jtd"

// ...

if (validate(data)) {
  // data is MyData here
  console.log(data.foo)
} else {
  // The type cast is needed, as Ajv uses a wider type to allow extension
  // You can extend this type to include your error types as needed.
  for (const err of validate.errors as JTDErrorObject[]) {
    switch (err.keyword) {
      case "type":
        // err type is narrowed here to have "type" error params properties
        console.log(err.params.type)
      break
        // ...
    }
  }
}
```
</code-block>
</code-group>

## Type-safe parsers and serializers

With typescript, your compiled parsers and serializers can be type-safe, either taking their type from schema type or from type parameter passed to compilation functions.

This example uses the same data and schema types as above:

<code-group>
<code-block title="JSON Type Definition">
```typescript
import Ajv, {JTDSchemaType} from "ajv/dist/jtd"
const ajv = new Ajv()

interface MyData {
  foo: number
  bar?: string
}

const schema: JTDSchemaType<MyData> = {
  properties: {
    foo: {type: "int32"}
  },
  optionalProperties: {
    bar: {type: "string"}
  }
}

// serialize will only accept data compatible with MyData
const serialize = ajv.compileSerializer(schema)

// parse will return MyData or undefined
const parse = ajv.compileParser(schema)

// types of parse and serialize are inferred from schema,
// they can also be defined explicitly:
// const parse = ajv.compileParser<MyData>(schema)

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

const invalidData = {
  unknown: "abc"
}

console.log(serialize(data))
console.log(serialize(invalidData)) // type error

const json = '{"foo": 1, "bar": "abc"}'
const invalidJson = '{"unknown": "abc"}'

console.log(parseAndLogFoo(json)) // logs property
console.log(parseAndLogFoo(invalidJson)) // logs error and position

function parseAndLogFoo(json: string): void {
  const data = parse(json) // MyData | undefined
  if (data === undefined) {
    console.log(parse.message) // error message from the last parse call
    console.log(parse.position) // error position in string
  } else {
    // data is MyData here
    console.log(data.foo)
  }
}
```
</code-block>
</code-group>

## Type-safe unions

JSON Type Definition only supports tagged unions, so unions in JTD are fully supported for `JTDSchemaType` and `JTDDataType`.
JSON Schema is more complex and so `JSONSchemaType` has limited support for type safe unions.

`JSONSchemaType` will type check unions where each union element is fully specified as an element of an `anyOf` array or `oneOf` array.
Additionally, unions of primitives will type check appropriately if they're combined into an array `type`, e.g. `{type: ["string", "number"]}`.

::: warning TypeScript limitation
Note that due to current limitation of TypeScript, JSONSchemaType cannot verify that every element of the union is present, and the following example is still valid `const schema: JSONSchemaType<number | string> = {type: "string"}`.
:::

Here's a more detailed example showing several union types:

<code-group>
<code-block title="JSON Schema">
```typescript
import Ajv, {JSONSchemaType} from "ajv"
const ajv = new Ajv()

type MyUnion = {prop: boolean} | string | number

const schema: JSONSchemaType<MyUnion> = {
  anyOf: [
    {
      type: "object",
      properties: { prop: { type: "boolean" } },
      required: ["prop"],
    },
    {
      type: ["string", "number"]
    }
  ]
}
```
</code-block>
</code-group>