is-my-json-valid: a JSON Schema validator that compiles
A JSONSchema validator that uses code generation to be extremely fast
At a glance
- What is it?
- Most JSON Schema validators interpret a schema on every call. is-my-json-valid compiles the schema into generated JavaScript once, and then runs that, which is why it has historically been the fastest option in the standard JavaScript schema benchmark suites. The price is a slightly unusual API and a fixed conformance story.
- Who is it for?
- is-my-json-valid suits a service that validates the same shapes on every request, where the schema is known at startup and the compilation cost is paid once, and where the fastest available validator is worth the small dependency tree.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 59 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The idea is to compile, not interpret
The description gives the whole design in one line: a JSON Schema validator that uses code generation to be extremely fast.
The performance section explains what that means concretely. The library uses code generation to turn your JSON schema into basic JavaScript code that is easily optimisable by the JavaScript engine. So a schema is not data that is walked at validation time, it is a program that is generated once and then called.
The reason this is fast is fairly obvious in hindsight. An interpreting validator has to look up the rule for each property, decide which rule applies, and apply it, for every value it checks, on every request. A generated validator has that decision baked into the control flow of a function, so the engine's optimiser can see the shape of the work and specialise on it.
The claim about speed is stated with a time stamp. At the time of writing, the library is the fastest validator when running a list of named benchmark suites, five of them, covering a general schema benchmark, a comparison of Node modules, and three others. The readme asks for a pull request if there are other relevant benchmarks, which is a small sign of a project that is aware its claim is only as good as the benchmarks behind it.
The trade is worth stating plainly. A generated validator is fast but it is also opaque, and a stack trace in a validator is a stack trace in generated code. The dependency list bears this out, with two packages whose only job is to write JavaScript.
The conformance statement is the other thing to note at the top of the readme. It passes the entire JSON Schema version four test suite except for remote references, and for the length rules when the input uses unicode surrogate pairs.
Compile once, validate many times
The usage section is short, and the shape of it is the API.
You pass a schema to the validator factory, and you get back a function.
var validate = validator({That function takes a document and returns a boolean, and the errors from the last call are available on it as a property, which is how you get the reason a document was rejected without paying for error objects on every successful validation.
There are two variations on the input. You can pass the schema as a string instead of an object, and there is a separate require submodule that loads a schema from a file relative to the module directory, so a schema on disk can be loaded with one call.
The distinction between a compiled validator and an interpreted one matters for how you use it. Compiling costs something, so a validator should be created once at startup and reused. A server that compiles a schema per request has thrown away the entire advantage, and a server that compiles once at startup has the cheapest validation the JavaScript ecosystem offers.
That is also the shape of the type safety story in the readme, where the validator is created once outside the request handler and used inside it, and the request body is typed as any before the check and as the schema's interface after it.
Options: formats, external schemas, verbosity and greed
The options are where the library earns its keep beyond the fast path, and each one is a small, well chosen addition.
Custom formats are the first. The library supports the formats specified in version four of JSON schema, such as date-time, and you can add your own by passing them in the formats option, where each format is a regular expression.
var validate = validator({
type: 'string',
required: true,
format: 'only-a'
}, {External schemas are the second. You pass schemas you reference with the reference attribute in the schemas option, and the reference is a name rather than a document identifier, which is a simpler model than the specification's own.
var validate = validator(schema, {schemas: {ext: ext}})Verbose mode is the third, and it is the one a debugging session needs. When it is set, the errors carry the value that caused the failure and a path, given as an array of keys, indicating which sub-schema failed. The readme shows how to turn that path back into the actual rule, and it does so with three different libraries, including a functional one, to make the point that the path is a standard pointer into the schema rather than a private format.
var schemaPath = validate.errors[0].schemaPathGreedy mode is the fourth. By default the validator bails on the first error, and in greedy mode it tries to validate as much as possible, so you get the whole list of problems in one pass rather than fixing them one at a time.
There is also a filter variant, a separate function that returns a document with the properties not in the schema removed, which is a convenient way to sanitise an object against a schema rather than merely reject it.
The error vocabulary, which is part of the API
There is a section listing the possible error message values, and it is worth reading because those strings are the library's public surface for anyone who displays validation errors to a user or maps them to codes.
The list covers the required rule, the type rule, additional items, a format rule that names the format from the schema, uniqueness, enumerations, unmet dependencies, additional properties, a referenced schema that does not match, a negative schema that matches, a pattern mismatch, and the several ways a combined schema can fail to match. Then the length and count rules, in both directions, and the minimum and maximum rules.
Two things are worth noticing about the format. The errors carry a field path, and the example shows a path like data.hello, which means the failing property is identified by a dotted path from the root of the document rather than by an index into an array. And the messages are short, lowercase, and grammatical in the sense of being a fragment, so they need a prefix to be readable, which is a design decision about how the library expects to be used.
The verbose mode example shows the full shape of one error, with the field, the message, the value, the expected type and the schema path, so a caller that turns on verbose mode gets everything it needs to build a precise message.
TypeScript support, with an honest caveat
The typings section is short and starts by admitting something.
The library ships with TypeScript typings, and the readme says they are still early on and not perfect at the moment, but should hopefully handle the most common cases, and asks for an issue if something does not work. The typings use the unknown type and therefore require TypeScript 3.0 or later.
The idea behind them is the interesting part. The typings construct an interface from the schema you pass in, so the request body is typed as anything before the check and as the schema's own shape after it.
const personValidator = createValidator({
type: 'object',
properties: {
name: { type: 'string' },
age: { type: 'number' },
},
required: [
'name'
]
})The example wires it into an Express handler, and the comments in the code mark the two points where the type changes, before the validation and after it. That is a genuine improvement over the usual situation where a request body is typed as anything for the whole of the handler because the schema is not visible to the type checker.
The caveat is worth repeating in your own evaluation. A type derived from a schema is only as good as the schema, and the readme's own wording about the typings being early and imperfect is the honest position of a feature that works well often enough to be useful.
The package, and the state of the tree
The manifest shows a small package with an interesting dependency list.
The version is 2.20.6, the licence is MIT, and the published files are just four, the main module, the format definitions, the require submodule and the type declarations. The dependencies are five: a package that generates a function from a body of code, a package that generates a property access expression, a package that validates IP addresses, a JSON pointer implementation, and a utility for extending objects.
The two code generation packages are the interesting ones, because they are the mechanism rather than the domain. The IP address package is there because the schema format has an address format, and the JSON pointer package supports the schema path feature. That is the entire dependency footprint for a validator that compiles schemas.
The test setup is a tape run over the test files followed by a TypeScript compilation, so the type declarations are checked on every test run rather than in a separate job. The development dependencies are the test runner, the TypeScript compiler, and a package for testing regular expressions safely, which is a sensible precaution for a library whose main input is user-supplied patterns.
The repository is small and flat, with the implementation and the type declarations at the root, a test directory, a security policy, an example file, and a Travis configuration. There are no GitHub releases to point at, and the last push was on 2026-08-25 with the repository not archived.
So the picture is a small, dependency-light, fast library whose main risk is not the code but the age of the standard it implements. If you need anything other than the fourth draft of the schema specification, this is not the library for you, and if you do need that draft, the conformance statement and the speed claim are both documented well enough to decide on.
Editorial conclusion
is-my-json-valid suits a service that validates the same shapes on every request, where the schema is known at startup and the compilation cost is paid once, and where the fastest available validator is worth the small dependency tree. It is a poor fit if you need a draft other than the fourth, since the conformance statement is tied to that draft, and it is a poor fit if you validate schemas that arrive at run time, because the compilation step only pays off when the schema is reused. Before you adopt it, check the known gaps against your schemas, in particular the length rules with surrogate pairs, and decide whether the generated-function approach is acceptable to you as a dependency.
Frequently asked questions
How does is-my-json-valid achieve its speed?
By code generation. It turns your schema into basic JavaScript that is easily optimisable by the JavaScript engine, so the validation rules are baked into a generated function rather than interpreted on every call. The readme claims it was the fastest validator in the benchmark suites it lists, at the time of writing.
How do I get the reason a document failed validation?
The compiled validator exposes the errors from the last call on its errors property, with each error carrying a field path such as data.hello and a short message. With the verbose option set, the errors also carry the value that caused the failure and a schema path pointing at the rule that was broken.
Can I use my own formats and reference other schemas?
Yes to both. Custom formats are passed in the formats option as regular expressions, and external schemas are passed in the schemas option and referenced by name with the reference attribute, with the referenced schema supplied under that name.
Does is-my-json-valid implement the latest JSON Schema draft?
No. The readme states that it passes the entire JSON Schema version four test suite, except for remote references and the length rules when using unicode surrogate pairs. It also supports the formats specified in version four of the specification.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/mafintosh-is-my-json-valid)Was this useful?