JSON mode and Structured Outputs solve different failures. JSON mode gives an application valid JSON. Structured Outputs adds a schema contract, so required keys, types and allowed values can be enforced by the model’s output mechanism.

That distinction matters when downstream code expects more than a document it can parse.

The short answer

Use JSON mode when any valid JSON object will do and your application already validates the shape. Use Structured Outputs when the response must match a supported JSON Schema and a missing field or unexpected enum value would break the next step.

Capability JSON mode Structured Outputs
Produces valid JSON Yes Yes
Enforces your schema No Yes
Requires application validation Yes Still recommended
Can represent a refusal separately API-specific Yes, in supported responses
Best fit Flexible machine-readable text Typed application data

OpenAI’s current guide recommends Structured Outputs where the feature is supported. JSON mode remains useful for older models or deliberately loose objects.

Valid JSON is not a valid business object

This is valid JSON:

{"status":"done","total":"thirty"}

It can still violate an application’s contract if total must be an integer or if status only permits queued, paid and failed.

A parser answers, “Can I read this document?” A schema validator answers, “Does this document have the fields and value types my program accepts?” JSON mode handles the first question. Structured Outputs is designed for the second.

What strict schema adherence changes

With Structured Outputs, the request includes a JSON Schema and enables strict adherence. The model is constrained to the supported structure rather than merely being prompted to imitate it.

A small response schema might require:

{
  "type": "object",
  "properties": {
    "invoice_id": {"type": "string"},
    "amount_cents": {"type": "integer"},
    "currency": {"type": "string", "enum": ["USD", "EUR"]}
  },
  "required": ["invoice_id", "amount_cents", "currency"],
  "additionalProperties": false
}

The constraint prevents an ordinary successful response from replacing amount_cents with prose or inventing an extra field. It does not prove that the amount is factually correct. Schema adherence is a format guarantee, not a verification of the underlying claim.

Function calling and response formatting are different choices

OpenAI exposes structured schemas in two common places:

  • function calling, when the model is selecting a tool and supplying its arguments;
  • structured response formatting, when the model’s answer itself should become a typed object for the application.

Choose function calling for an action boundary. A payment lookup, database query or support-ticket creation should be represented as a tool call that the application authorizes and executes.

Choose a structured response format when the application wants to render or store the answer itself, such as extracted invoice fields or a set of UI cards.

Do not use a response schema as a substitute for permission checks. A valid tool argument can still request an action the user is not allowed to perform.

The schema is a contract with limits

Structured Outputs supports much of JSON Schema, but not every feature. Check the current supported-schema section before designing a deeply recursive or highly conditional type.

Keep the contract narrow:

  1. require every field the application truly needs;
  2. use enums for closed choices;
  3. set additionalProperties deliberately;
  4. describe units in field names, such as amount_cents;
  5. separate nullable values from missing values;
  6. version the schema when consumers cannot change together.

The OpenAI guide also recommends generating schemas from native SDK types where possible. That reduces drift between a TypeScript or Python model and a separately maintained JSON file.

Refusals and incomplete responses still need branches

A schema-constrained call can end without a normal object. A model may refuse a request, a response may be incomplete, or the transport may fail.

Production code needs separate handling for:

  • a completed structured value;
  • a refusal;
  • a length or other incomplete status;
  • a timeout or network failure;
  • a value that the client library could not parse.

Do not cast every response body to the success type. Check the API status and content variant first.

Streaming changes when data becomes usable

Structured data can be streamed, but a partial JSON fragment is not automatically a complete object. SDK helpers can expose incremental events while maintaining the schema-aware parser.

Decide whether the interface genuinely benefits from early fields. For a small extraction, waiting for the complete validated object is simpler. For a long generated plan, the application might render sections as they arrive while postponing side effects until final validation succeeds.

Never trigger an irreversible action from an unfinished fragment.

Validation still belongs in the application

Even with strict schema adherence, validate the object at the boundary. The application may enforce rules the schema cannot establish:

  • an identifier exists in your database;
  • an amount is within the user’s approved limit;
  • two dates are in a permitted order;
  • a URL belongs to an allowed host;
  • a tool call is authorized for this account.

Treat Structured Outputs as one layer in a pipeline: model constraint, client parsing, application validation and business authorization.

When JSON mode is the better fit

JSON mode is reasonable when the shape is intentionally open, the model in use does not support Structured Outputs, or a mature validator already accepts several compatible variants.

If you use it, explicitly ask for JSON, validate every response, cap retries and preserve the validation error for debugging. A retry loop without a limit can turn one malformed response into latency and cost spikes.

The prompt caching guide covers a separate concern: reducing repeated prompt work. Caching does not strengthen the output contract.

A practical migration

To move an existing JSON-mode endpoint:

  1. collect the objects the endpoint currently emits;
  2. define the smallest schema that accepts the intended variants;
  3. add explicit branches for refusal and incomplete responses;
  4. test missing fields, unexpected enums and null values;
  5. compare schema and application types in CI;
  6. move one consumer at a time;
  7. log validation categories without storing sensitive payloads.

Run evals with realistic inputs. A perfect schema match can still contain a wrong classification or extraction.

Sources and version note

This guide was checked on October 28, 2026 against OpenAI’s Structured Outputs guide and Responses API reference. Supported models, schema keywords and SDK helpers can change; verify the current documentation for the API and model you deploy.