1 A JSON schema package for Go | Google Open Source Blog

opensource.google.com

Menu

A JSON schema package for Go

Wednesday, January 21, 2026

JSON Schema is a specification for describing JSON values that has become a critical part of

LLM infrastructure. We recently released github.com/google/jsonschema-go/jsonschema, a comprehensive JSON Schema package for Go. We use it in the official Go SDK for MCP and expect it to become the canonical JSON Schema package for Google's Go SDKs that work with LLMs.

JSON Schema has been around for many years. Why are we doing this now, and what do LLMs have to do with it?

JSON is a flexible way to describe values. A JSON value can be null, a string, a number, a boolean, a list of values, or a mapping from strings to values. In programming language terms, JSON is dynamically typed. For example, a JSON array can contain a mix of strings, numbers, or any other JSON value. That flexibility can be quite powerful, but sometimes it's useful to constrain it. Think of JSON Schema as a type system for JSON, although its expressiveness goes well beyond typical type systems. You can write a JSON schema that requires all array elements to be strings, as you could in a typical programming language type system, but you can also constrain the length of the array or insist that its first three elements are strings of length at least five while the remaining elements are numbers.

The ability to describe the shape of JSON values like that has always been useful, but it is vital when trying to coax JSON values out of LLMs, whose output is notoriously hard to constrain. JSON Schema provides an expressive and precise way to tell an LLM how its JSON output should look. That's particularly useful for generating inputs to tools, which are usually ordinary functions with precise requirements on their input. It also turns out to be useful to describe a tool's output to the LLM. So frameworks like MCP use JSON Schema to specify both the inputs to and outputs from tools. JSON Schema has become the lingua franca for defining structured interactions with LLMs.

Requirements for a JSON Schema package

Before writing our own package, we took a careful look at the existing JSON Schema packages; we didn't want to reinvent the wheel. But we couldn't find one that had all the features that we felt were important:

  1. Schema creation: A clear, easy-to-use Go API to build schemas in code.
  2. Serialization: A way to convert a schema to and from its JSON representation.
  3. Validation: A way to check whether a given JSON value conforms to a schema.
  4. Inference: A way to generate a JSON Schema from an existing Go type.

We looked at the following packages:

It didn't seem feasible to cobble together what we needed from multiple packages, so we decided to write our own.

A Tour of jsonschema-go

A Simple, open Schema struct

At the core of the package is a straightforward Go struct that directly represents the JSON Schema specification. This open design means you can create complex schemas by writing a struct literal:


var schema = &jsonschema.Schema{
  Type:        "object",
  Description: "A simple person schema",
  Properties: map[string]*jsonschema.Schema{
    "name": {Type: "string"},
    "age": {Type: "integer", Minimum: 0.0},
  },
  Required: []string{"name"},
}

A Schema will marshal to a valid JSON value representing the schema, and any JSON value representing a schema can be unmarshalled into a Schema.

The Schema struct defines fields for all standard JSON Schema keywords that are defined in popular specification drafts. To handle additional keywords not present in the specification, Schema includes an Extra field of type map[string]any.

Validation and resolution

Before using a schema to validate JSON values, the schema itself must be validated, and its references to other schemas must be followed so that those schemas can themselves be checked. We call this process resolution. Calling Resolve on a Schema returns a jsonschema.Resolved, an opaque representation of a valid schema optimized for validation. Resolved.Validate accepts almost any value that can be obtained from calling json.Umarshal: null, basic types like strings and numbers, []any, and map[string]any. It returns an error describing all the ways in which the value fails to satisfy the schema.


rs, err := schema.Resolve(nil)
if err != nil {
  return err
}
err = rs.Validate(map[string]any{"name": "John Doe", "age": 20})
if err != nil {
  fmt.Printf("validation failed: %v\n", err)
}

Originally, Validate accepted a Go struct. We removed that feature because it is not possible to validate some schemas against a struct. For example, If a struct field has a non-pointer type, there is no way to determine whether the corresponding key was present in the original JSON, so there is no way to enforce the required keyword.

Inference from Go types

While it's always possible to create a schema by constructing a Schema value, it's often convenient to create one from a Go value, typically a struct. This operation, which we call inference, is provided by the functions For and ForType. Here is For in action:


type Person struct {
    Name string `json:"name" jsonschema:"person's full name"`
    Age int `json:"age,omitzero"`
}

schema, err := jsonschema.For[Person](nil)

/* schema is:
{
    "type": "object",
    "required": ["name"],
    "properties": {
        "age":  {"type": "integer"},
        "name": {
            "type": "string",
            "description": "person's full name"
        }
    },
    "additionalProperties": false
}
*/

For gets information from struct field tags. As this example shows, it uses the name in the json tag as the property name, and interprets omitzero or omitempty to mean that a field is optional. It also looks for a jsonschema tag to get property descriptions. (We considered adding support for other keywords to the jsonschema tag as some other packages do, but that quickly gets complicated. We left an escape hatch in case we decide to support other keywords in the future.)

ForType works the same way, but takes a reflect.Type. It's useful when the type is known only at runtime.

A foundation for the Go community

By providing a high-quality JSON Schema package, we aim to strengthen the entire Go ecosystem for AI applications (and, indeed, any application that needs to validate JSON). This library is already a critical dependency for Google's own AI SDKs, and we're committed to its long-term health. We welcome external contributions, whether they are bug reports, bug fixes, performance enhancements, or support for additional JSON Schema drafts. Before beginning work, please file an issue on our issue tracker.

.