You can't audit what you can't define. When your LLM returns a user profile, incident report, or configuration change, you need to know exactly what fields you're getting, what types they are, and whether they meet your security requirements. That's where JSON Schema comes in.
Scope - What This Guide Covers
This guide shows you how to use JSON Schema to validate AI-generated outputs in production systems. You'll learn to write schemas that enforce data contracts between your AI components and downstream services, handle validation failures without breaking your pipeline, and decide when JSON Schema's complexity might not be worth the overhead.
We're focused on runtime validation of LLM outputs. This isn't about training data validation or model governance. If you're integrating GPT-4, Claude, or internal models into your API layer, authentication system, or incident response workflow, this guide is for you.
Key Concepts and Definitions
JSON Schema is a vocabulary for annotating and validating JSON documents. First proposed by Kris Zyp in 2007, it's now the standard for describing JSON structure. Think of it as a type system for JSON: you define what fields must exist, what types they should be, and what constraints they must satisfy.
Validation happens at runtime. Your schema acts as a contract: the AI promises to return data in a specific shape, and your validator checks that promise before passing the data to business logic.
Non-determinism is the core challenge. Traditional APIs return predictable structures. LLMs don't. The same prompt can produce different field orders, optional fields that appear inconsistently, or creative interpretations of your instructions. JSON Schema forces determinism onto non-deterministic outputs.
Structured output modes (like OpenAI's JSON mode or function calling) help, but they're not validation. They increase the likelihood of valid JSON, but they don't guarantee your schema requirements are met. You still need to validate.
Requirements Breakdown
Schema Design for AI Outputs
Start with required fields only. Don't make everything required just because your database schema does. AI outputs often include partial information, especially in streaming scenarios or when context is limited.
Define explicit types and formats. Use "type": "string", "format": "email", and "pattern" constraints. LLMs are good at following type hints but terrible at inferring implicit requirements.
Set bounds on arrays and strings. Use minItems, maxItems, minLength, and maxLength. Without these, your LLM might return a 50,000-character justification field that breaks your database or a 200-item array that times out your renderer.
Example schema for an AI-generated security alert:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"required": ["severity", "description", "affected_systems"],
"properties": {
"severity": {
"type": "string",
"enum": ["critical", "high", "medium", "low"]
},
"description": {
"type": "string",
"minLength": 10,
"maxLength": 500
},
"affected_systems": {
"type": "array",
"items": {"type": "string"},
"minItems": 1,
"maxItems": 50
},
"remediation_steps": {
"type": "array",
"items": {"type": "string"}
}
}
}
Validation Strategy
Validate before persistence. Don't write AI outputs to your database until they pass schema validation. This prevents corrupt data from entering your system and makes debugging easier.
Log validation failures with the full output. You need to see what the LLM actually returned, not just that it failed validation. Include the prompt, the response, and the specific validation errors.
Implement retry logic with schema feedback. When validation fails, include the schema and the validation errors in your retry prompt. LLMs can often self-correct when you show them what went wrong.
Set a retry limit. Three attempts is reasonable. After that, escalate to human review or fail gracefully. Don't let validation loops consume your API budget.
Implementation Guidance
Choosing a Validator
For Node.js, use Ajv (Another JSON Schema Validator). It's fast, supports draft 2020-12, and handles custom formats well. Install with npm install ajv ajv-formats.
For Python, use jsonschema or fastjsonschema. The former is more feature-complete, the latter is faster for high-throughput scenarios.
For Go, gojsonschema is the standard choice. It's slower than native Go validation but handles complex schemas correctly.
Integration Pattern
Wrap your LLM client with a validation layer:
def validated_llm_call(prompt, schema, max_retries=3):
for attempt in range(max_retries):
response = llm_client.complete(prompt)
try:
parsed = json.loads(response)
validate(parsed, schema)
return parsed
except ValidationError as e:
if attempt == max_retries - 1:
log_failure(prompt, response, e)
raise
prompt = f"{prompt}\n\nPrevious attempt failed validation: {e}\nPlease correct and try again."
This pattern works for most use cases. For streaming outputs, validate incrementally if your schema allows it, or buffer the full response before validation.
Monitoring and Alerting
Track your validation failure rate. If it's above 5%, your schema is too strict or your prompts aren't clear enough. If it's below 0.1%, your schema might not be catching real problems.
Alert on sudden spikes. A jump from 2% to 15% failures suggests a prompt change, model update, or upstream data issue.
Common Pitfalls
Over-constraining optional fields. Don't make a field required just because you want it. LLMs often omit fields they don't have information for, and that's usually correct behavior.
Ignoring additionalProperties. By default, JSON Schema allows extra fields. Set "additionalProperties": false if you want strict validation, but be aware this makes schemas brittle when you add fields.
Validating too late. If you validate after writing to a queue or database, you've already propagated bad data. Validate at the boundary between the LLM and your system.
Not versioning schemas. When you change a schema, you break existing prompts and integrations. Use $id and version numbers in your schema URIs. Store old versions for rollback.
Treating validation as security. JSON Schema validates structure, not content. It won't catch SQL injection in a string field or XSS in a description. You still need input sanitization and parameterized queries.
Quick Reference Table
| Scenario | Schema Constraint | Example |
|---|---|---|
| Limit field length | maxLength |
"maxLength": 500 |
| Require specific values | enum |
"enum": ["approved", "rejected"] |
| Validate email format | format |
"format": "email" |
| Ensure array not empty | minItems |
"minItems": 1 |
| Prevent extra fields | additionalProperties |
"additionalProperties": false |
| Require nested object | required + properties |
See example schema above |
| Validate URL format | format + pattern |
"format": "uri" |
| Set numeric range | minimum, maximum |
"minimum": 0, "maximum": 100 |
Competing Standard Note: JSON Structure was published in July 2025 by Microsoft's Clemens Vasters as a simpler alternative to JSON Schema. It's cleaner and easier to write, but tooling is limited and it's not yet widely adopted. Stick with JSON Schema for production systems until JSON Structure validators mature and gain ecosystem support.



