For extraction, classification, and any machine-consumed answer, there are two broad designs. Structured output: pass output_config: {"format": {"type": "json_schema", "schema": {...}}} and Claude's response is constrained to your JSON Schema — generally available on the Claude API and supported on Vertex AI, Bedrock (subset), Foundry, and Claude Platform on AWS. Prose-with-extraction: let Claude answer naturally and pull the fields out afterward with your own code (or, worse, a second model call). Since output tokens cost 5x input tokens on current models ($25 vs. $5 per MTok on Opus 4.8), the shape of the output dominates this comparison.
Where each approach spends tokens
JSON's overhead is syntax and keys. Every brace, quote, and repeated property name is an output token. A response like {"sentiment": "negative", "priority": "high"} spends a large fraction of its tokens on scaffolding around two short values — and in an array of 100 extracted records, the same key names are generated 100 times. Verbose schemas amplify this: key length is a per-record output cost you chose at design time.
Prose's overhead is politeness and hedging. Unconstrained answers arrive wrapped in preamble ("Looking at this ticket, I'd say..."), transitions, and caveats. For a five-field extraction, the wrapper often outweighs JSON's syntax — and then you still have to parse it, with a failure branch that triggers retries. Retries are billed in full; they are the hidden cost line of the prose approach. Note that on current models (Claude 4.6-generation onward) you can't force format by prefilling the assistant's reply — such requests return a 400 error; the documented migration path for format control is structured outputs itself.
Structured output's hidden costs are smaller and bounded. Grammar compilation adds latency to the first request but is cached automatically for 24 hours from last use (changing the schema invalidates it). Refusals return HTTP 200 with stop_reason: "refusal" and are billed even though output may not match the schema — handle that branch. And a response truncated by max_tokens may be invalid JSON, so budget output room.
A rough decision table
| Situation | Cheaper approach | Why |
|---|---|---|
| Few fields, machine-consumed, high volume | Structured output, short keys | No preamble, no retries, no second parse step |
| Long-form answer a human reads | Free text | JSON adds pure overhead around content that wanted to be prose |
| Many records per response | Structured output, aggressively short keys | Key names repeat per record at output rates |
| Quotes/evidence from documents | Citations feature | cited_text doesn't count toward output tokens — cheaper than prompting for quotes |
That last row is an under-used official lever: enabling citations on document blocks is documented as efficient on output tokens compared with asking for quotes in the response, because the quoted text itself is not billed as output. One constraint — citations cannot be combined with output_config.format in the same request (400 error), so it is an alternative to JSON mode, not an add-on.
Design rules that cut the JSON bill
Keep keys short but readable (qty, not total_quantity_of_items_ordered). Set additionalProperties: false as the docs require. Don't model prose as JSON — a "reasoning" field invites a paragraph at output rates; if you don't need it downstream, delete it. In Python, client.messages.parse() with Pydantic models gives you the schema, transformation of unsupported constraints, and client-side validation in one step.
usage.output_tokens. Include the retry rate of the prose parser in the comparison — a 5% retry rate adds 5% to the whole bill, not just the output.Where to go next
Related levers: output length budgeting, right-sizing max_tokens, and input vs. output economics.