Library / SDK
santhosh-tekuri/jsonschema avatar
santhosh-tekuri/jsonschema

jsonschema v6 validates against five JSON Schema drafts, with assertions you opt into

JSONSchema (draft 2020-12, draft 2019-09, draft-7, draft-6, draft-4) Validation using Go

1,289 stars146 forksGoApache-2.0

At a glance

What is it?
The santhosh-tekuri/jsonschema library is a Go implementation of JSON Schema that supports drafts 2020-12, 2019-09, draft-7, draft-6 and draft-4, and passes the official JSON-Schema-Test-Suite apart from the optional tests. Format and content assertions are off by default and are enabled per draft, and the jv command line tool ships with its own version line, separate from the library.
Who is it for?
jsonschema v6 fits a Go service that has to accept documents against a schema that a client controls, and that needs the difference between a missing optional assertion and a real violation to be visible in the error output. It is the wrong choice if you want format and content assertions on by default, because both are flags rather than defaults.
Can I use it commercially?
Yes. Apache-2.0 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 5 days ago.
What is it written in?
Mainly Go, 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

Five drafts, one implementation

The library validates JSON against JSON Schema, and the scope of the drafts it covers is stated in the repository description: draft 2020-12, draft 2019-09, draft-7, draft-6 and draft-4.

That range matters more than it looks. The drafts differ in substance, not just in version numbers, and the older ones are still in use in the wild. A service that has to accept a document against a schema written four drafts ago cannot simply upgrade its validator and assume the meaning of the schema is unchanged.

The way the project argues for correctness is worth noting, because it is a measurement rather than a claim. The library passes the JSON-Schema-Test-Suite from the json-schema-org organisation, excluding the optional tests, and the README links to bowtie, the JSON Schema test runner, to compare with other implementations. Each draft has its own compliance badge, for draft-04, draft-06, draft-07, 2019-09 and 2020-12.

The test suite is the standard way to say something about a validator that a benchmark cannot. It enumerates the corner cases of each keyword, and an implementation that passes it behaves the same way as the reference implementations for those cases. What the badges do not tell you is how the library behaves on the schemas nobody wrote a test for, and the optional tests, which are excluded here, are the ones that would tell you that.

The project also handles the case where a schema is its own problem. It detects infinite loop traps, both a $schema cycle and a validation cycle, which is the sort of thing that turns a validation library into a denial of service vector against your own service.

Vocabulary based validation is how one binary handles five dialects

The mechanism behind supporting several drafts at once is vocabulary based validation, and the feature list names it directly, along with mixed dialect support and a custom vocabulary option.

In the 2019-09 and 2020-12 drafts, the specification was restructured so that a dialect is a set of vocabularies, each covering a group of keywords, and a schema declares which vocabularies it uses through the $vocabulary keyword. That is a structural change rather than a cosmetic one, and it is what allows a validator to treat draft-7 and draft-2020-12 as data rather than as separate code paths.

The library exposes that mechanism in both directions. A custom vocabulary can be enabled via $vocabulary for draft 2019-09 and later, and via a flag for draft 7 and earlier, where the keyword does not exist. And a custom $schema url is supported, so a schema can point at a dialect the validator does not know by default.

The interesting consequence is mixed dialect support, which means a document can be validated against a schema that borrows keywords from different drafts. For a service that accepts schemas from many clients, that is the difference between rejecting a schema and accepting it, and it is the kind of behaviour that the test suite badges do not describe but that a real deployment depends on.

The compiler files at the repository root match this design. There are compiler.go and objcompiler.go, loader.go for resolving and fetching schemas, draft.go for the draft handling, vocab.go for the vocabulary machinery, and a metaschemas/ directory holding the meta-schemas the implementation ships.

Assertions are flags, and the draft decides whether they exist

Two families of assertion in the specification are opt-in in this library, and the rule in both cases is tied to the draft.

Format assertions are the first. They are behind a flag to enable in draft 2019-09 and later, because that is where the specification promoted format from an annotation to an assertion. The built-in formats are a long list: regex and uuid, ipv4 and ipv6, hostname and email, date, time, date-time and duration, json-pointer and relative-json-pointer, uri, uri-reference and uri-template, iri and iri-reference, and period and semver. Custom format registration is supported, so an application can define its own format names and the semantics that go with them.

Content assertions are the second family, behind a flag to enable in draft 7 and later. They cover contentEncoding, with base64 and custom support, contentMediaType, with application/json and custom support, and contentSchema, which is a schema applied to the decoded content.

The design decision here is a deliberate refusal to be permissive by default. A validator that treats format as an assertion by default will reject documents that the specification says are valid, and a validator that ignores it will accept documents that other validators reject. Neither behaviour is universally right, so the library makes the caller decide, and the CLI exposes the same decision through a flag.

The one asymmetry is worth noting. The format flag is described as applying in draft 2019 and later, and the content flag in draft 7 and later, so a schema written in an older dialect can still have format assertions turned on, while a draft 2020 schema with content assertions needs a different flag.

The jv CLI has its own version line

The command line tool is installed with a single go install command.

bash
go install github.com/santhosh-tekuri/jsonschema/cmd/jv@latest

The version note is the part that matters for a team. The CLI is versioned independently, and you can see that in the git tags under cmd/jv, with the current one being cmd/jv/v0.7.0, while the library itself is on v6.

That is a deliberate separation. The library is a Go module that applications depend on, and it follows the major version rules of the Go module system, where v6 means the import path carries the /v6 suffix. The CLI is a tool that people run, and it does not need to break its interface every time the library changes shape. The cost is that you now have two version numbers to track, and the benefit is that the tool can stay stable while the library moves.

The usage is a single command with a schema and zero or more instances.

code
Usage: jv [OPTIONS] SCHEMA [INSTANCE...]

Options:
  -c, --assert-content    Enable content assertions with draft >= 7
  -f, --assert-format     Enable format assertions with draft >= 2019
      --cacert pem-file   Use the specified pem-file to verify the peer. The file may contain multiple CA certificates
  -d, --draft version     Draft version used when '$schema' is missing. Valid values 4, 6, 7, 2019, 2020 (default 2020)
  -h, --help              Print help information
  -k, --insecure          Use insecure TLS connection
  -o, --output format     Output format. Valid values simple, alt, flag, basic, detailed (default "simple")
  -q, --quiet             Do not print errors
  -v, --version           Print build information

The -d flag is what a pipeline needs, because it sets the draft used when the $schema keyword is missing, and the default is 2020, which is the newest dialect rather than the most permissive one.

Exit codes and output formats decide how it fits in a pipeline

The CLI feature list is short and specific, and it describes the contract a script depends on.

The exit code is 1 for validation errors and 2 for usage errors, which is the distinction a shell script needs in order to tell a document that failed the schema from a command that was invoked wrongly. It validates both the schema and multiple instances, so a bad schema and a bad document are separate failures rather than one. It supports both JSON and YAML files, and standard input through a dash, and it accepts http and https URLs, with custom certificate authorities through --cacert and a flag to skip certificate verification entirely.

The output format is the other half. There are five, and they are not variations on a theme. The simple format is the default. The alt format is the alternative display with a # prefix, which is the display that the error hierarchy section describes as introspectable. The flag format is the short form for scripts, and basic and detailed are the two levels of the full error report.

The error model itself is what the library is really for. Errors are introspectable, and they have a hierarchy, which means a caller in Go can walk the tree of what went wrong rather than parsing a string. The alternative display with # is the same information rendered for a human, and the basic and detailed outputs are two depths of the same report.

That is the difference between the two ways of using the project. As a library inside your service, the structured error tree is what you consume, and you decide how to present it. As the CLI, you get the same information rendered for a terminal or captured by a script, and the exit code tells you whether to fail the pipeline.

A custom regex engine and the reason the module needs two dependencies

The dependency list is short enough to be worth reading closely, because the comments in it are not decoration.

The module is github.com/santhosh-tekuri/jsonschema/v6, it requires Go 1.21, and it has exactly two direct dependencies. github.com/dlclark/regexp2 at v1.11.0 is marked as used for testing, and golang.org/x/text at v0.14.0 has no comment.

The regexp2 entry explains one of the feature list items. The library has a custom regex engine, and the reason a second regular expression library is needed for the tests is that the standard library engine does not implement the pattern syntax that the JSON Schema specification requires, so the tests need a conforming implementation to compare against.

The other feature that needs an implementation of its own is Unicode handling, and x/text is the standard Go library for that. The format list in the README includes formats that depend on it, such as email, hostname and iri, which are defined in terms of Unicode rather than ASCII.

The rest of the repository shows the shape of the implementation. There is a kind/ directory, which is where the JSON value kinds are modelled, a metaschemas/ directory for the meta-schemas, and a testdata/ directory alongside a suite_test.go that runs the official test suite. The vocabulary and error work is split across vocab.go, output.go and position.go, and position.go is worth noting because error messages that point at a location in the document are the difference between a validation failure a developer can act on and one they cannot.

On maintenance, the licence is Apache 2.0, the newest release is v6.0.3 from 2026-08-06, the last push was on 2026-09-21, and the project is not archived. The default branch is called boon rather than main, which is unusual enough to be worth knowing before you clone it.

Editorial conclusion

jsonschema v6 fits a Go service that has to accept documents against a schema that a client controls, and that needs the difference between a missing optional assertion and a real violation to be visible in the error output. It is the wrong choice if you want format and content assertions on by default, because both are flags rather than defaults. Verify first which draft your schemas use, since the assertion flags depend on it, and note that the v6 module path means the import path changed, so upgrading is a source level change rather than a version bump.

Frequently asked questions

Which JSON Schema drafts does the jsonschema library support?

Draft 2020-12, draft 2019-09, draft-7, draft-6 and draft-4, and the library passes the official JSON-Schema-Test-Suite apart from the optional tests, with a separate compliance badge for each draft.

How do I install the jv command line tool?

Run go install github.com/santhosh-tekuri/jsonschema/cmd/jv@latest. The CLI is versioned independently of the library, and you can see that in the git tags under cmd/jv, where the current one is v0.7.0.

Why are format and content assertions off by default?

Both are behind flags, and the draft decides when they apply: format assertions are enabled in draft 2019-09 and later, and content assertions in draft 7 and later. The specification promoted format from an annotation to an assertion in 2019-09, and a permissive default would reject documents other validators accept.

What exit codes does jv use?

Exit code 1 for validation errors and 2 for usage errors, so a script can tell a document that failed the schema from a command that was invoked wrongly. The output format is chosen with the -o flag, with valid values simple, alt, flag, basic and detailed.

Can I define my own format or vocabulary?

Yes. Custom format registration is supported for the built-in format list, and a custom vocabulary can be enabled through the $vocabulary keyword for draft 2019-09 and later, or through a flag for draft 7 and earlier. A custom $schema url is supported as well.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. README
  4. Releases
  5. santhosh-tekuri/jsonschema on GitHub
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/santhosh-tekuri-jsonschema.svg)](https://hysenlabs.com/projects/santhosh-tekuri-jsonschema)

Was this useful?