Reliability techniquesPatternProven

Structured outputs

Also called: JSON mode, schema-constrained generation, generateObject

Structured outputs constrain a model to return data matching a schema you define, rather than prose you have to parse. It removes an entire class of failure: the model answered correctly and your code could not read it.

James Phoenix
Understanding Data Updated July 26, 2026

Asking for JSON in the prompt and hoping is not a strategy. You get JSON most of the time, then a markdown code fence, then a helpful preamble, then a trailing comma, and your parser throws on input that was substantively correct.

Structured outputs make the shape a constraint rather than a request. You supply a schema, and the response conforms to it.

The shape

TypeScript
import { generateObject } from 'ai'
import { z } from 'zod'

const { object } = await generateObject({
  model: openai('gpt-5-mini'),
  schema: z.object({
    sentiment: z.enum(['positive', 'neutral', 'negative']),
    confidence: z.number().min(0).max(1),
    reasons: z.array(z.string()).max(3),
  }),
  prompt: review,
})

object.sentiment   // typed, parsed, and within the enum

The enum is doing real work: sentiment cannot come back as "quite positive" or "POSITIVE". You have made an entire category of downstream defensive code unnecessary.

Where it changes the most

  • Anything you branch on. A classification you route with must be one of a fixed set, or the routing has an undefined case.
  • Evaluation. A rubric score has to be aggregatable, which means parseable, which means schema-constrained.
  • Chained steps. In prompt chaining, one step's output is the next step's input. Loose shapes compound.

What it does not fix

A schema constrains form, not truth. The model will happily return a perfectly valid object with a confidently wrong sentiment, and confidence: 0.95 is a generated number, not a calibrated probability. Schema validation passing tells you the response is readable, not that it is right. That is still the job of evaluation.

Tip
Put the reasoning field before the answer field in your schema, and models tend to use it. Ordering the schema as { reasoning, answer } gives you something close to chain of thought for free; { answer, reasoning } produces a post-hoc justification of an answer already committed to.

Related terms

Engineering context for real systems?

Getting the right information into the window at the right time is most of the job. If you want that thinking applied to your product, that is what I do.

See how I can help