Structured outputs (JSON)

Claude API · Practical · 12 min

Programs need data they can trust to parse, not prose that is usually JSON.

Asking "reply in JSON" works most of the time, which is not good enough for a program. Structured outputs make Claude's reply follow a JSON Schema you supply, so the result always parses and has the fields you asked for.

There are two ways to use it in Python:

  • client.messages.parse(..., output_format=MyModel): pass a Pydantic model (a Python class that declares typed fields and validates data). The SDK builds the schema, sends it, and gives you a ready object in response.parsed_output.
  • client.messages.create(..., output_config={"format": {"type": "json_schema", "schema": {...}}}): send a schema yourself and json.loads the text block.

The feature is generally available. Older code used a top-level output_format request field with a beta header; that field is deprecated in favour of output_config.format.

For tools, the same guarantee comes from "strict": True on a tool definition, which makes the tool inputs match the schema.

Limits to know: schemas must set additionalProperties to false, and some JSON Schema features (number ranges, string lengths, recursive schemas) are not enforced. The first request with a new schema is a bit slower while it is compiled. A refusal or hitting max_tokens can still produce output that does not match, so check stop_reason first.

This also replaces an old trick: starting the assistant's answer with { (prefill), which current models reject.

Example

import anthropic
from pydantic import BaseModel

class Contact(BaseModel):
    name: str
    email: str
    wants_demo: bool

client = anthropic.Anthropic()
resp = client.messages.parse(
    model="claude-opus-5-5",
    max_tokens=512,
    messages=[{"role": "user", "content":
        "Extract: Jo Park (jo@example.com) asked us to book a demo next week."}],
    output_format=Contact,
)
contact = resp.parsed_output
print(contact.name, contact.email, contact.wants_demo)
# Jo Park jo@example.com True

Remember

  • messages.parse(output_format=Model) returns a validated object
  • Raw form: output_config={"format": {"type": "json_schema", ...}}
  • strict: True on a tool guarantees schema-valid tool inputs

Watch out for

  • Using the deprecated top-level output_format request field from older examples.

Check yourself

  1. What does structured outputs guarantee that a prompt saying 'reply in JSON' does not?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: platform.claude.com/docs/en/build-with-claude/structured-outputs