Getting structured outputs out of Claude
The problem structured outputs actually solve
Asking a model to "return JSON" in a plain-text instruction gets you JSON most of the time, and an occasional malformed response, a stray explanation before the JSON starts, or a field that's present sometimes and missing other times — none of which is a big deal for a person reading the output, and every one of which breaks a parser expecting a fixed, reliable shape downstream. Structured output support closes that gap by constraining what the model can produce to match a schema you define, rather than relying on the model interpreting a plain-language instruction about formatting correctly every single time.
Two different mechanisms, two different use cases
There are two related but distinct ways to get structured output out of Claude: defining a tool whose input schema is the shape you actually want (using a tool call as a structured-output mechanism even when you never intend to execute the "tool"), and specifying an output format directly for the response itself where that's supported. The tool-based approach is more broadly available and works well when the structured data is genuinely something you'd otherwise pass to a function; the direct-format approach is more purpose-built when you just need the final answer to conform to a schema and there's no real "tool" conceptually involved.
Why schema strictness matters more than it looks
A loosely-specified schema — optional fields left ambiguous about when they're actually expected, nested structures without clear types — produces output that's technically valid JSON but inconsistent in ways a parser downstream still has to handle defensively, which defeats a good part of the reason to use structured output in the first place. Write the schema as strictly as your actual use case allows: required fields required, enums constrained to the actual valid values rather than left as free-text strings, nested objects fully specified rather than left open-ended. A stricter schema also gives the model a clearer target, which tends to improve accuracy on the values themselves, not just the shape.
What structured output doesn't guarantee
Constraining the shape of a response doesn't constrain its correctness — a schema-valid response can still contain a wrong value in a well-formed field, because the schema controls structure, not content accuracy. Teams sometimes treat "it parsed cleanly" as equivalent to "it's correct," and those are genuinely different properties that need separate validation. Build a validation step for the actual values, not just a parse step for the shape, if the downstream use of the data has any real cost attached to it being wrong.
Handling the edge case where the model can't satisfy the schema
A schema that's technically satisfiable but represents an awkward fit for what the model is actually being asked to determine — forcing a confidence score into a field when the underlying task is genuinely ambiguous, say — tends to produce answers that are schema-valid but low-quality, because the model is filling a field it doesn't have a clean answer for rather than being given a way to express genuine uncertainty. Where genuine ambiguity is a real possibility, build a first-class way to represent "not confident" or "not applicable" into the schema itself, rather than forcing every response into a shape that assumes certainty.
Versioning a schema as your product evolves
A schema that's live in production and consumed by real downstream code isn't free to change casually — adding a required field breaks every caller expecting the old shape, and even loosening a field from required to optional changes what downstream validation logic can assume. Treat a production structured-output schema the way you'd treat a public API contract, with the same discipline around backward-compatible changes and the same care around anything that isn't one, rather than editing it ad hoc each time a new use case adds one more field to whatever happens to be convenient.
Related
If the structured data you're extracting doubles as an input to a function you'll actually call, see Claude tool use, a working quickstart for the tool-based path specifically, and handling Claude API errors without guessing for what to do when a response fails schema validation despite the constraint being in place.
Verified 2026-09-30 against ClaudeHow facts module (src/data/facts/) — see /about/#accuracy.