What are structured outputs? JSON that matches a schema
By Flavio
Structured outputs are answers that follow a JSON Schema you send with the request. How that differs from JSON mode in Claude Code, Codex, Cursor and Grok.
Structured outputs are model answers that follow a JSON Schema you send with the request. The schema decides the keys and the allowed values.
JSON that merely parses is a different setting. Jev structured outputs owns that split, with a routing example and a comparison against the Decisions API. This entry is the flag or API field in the four coding tools.
How structured outputs work
You declare a schema. The provider constrains the answer so the text is JSON that matches, within the schema features they support. Your code reads fields instead of scraping a paragraph.
A match means the keys and the enums are the ones you allowed. It does not mean the values are true. OpenAI’s guide says structured outputs stop a missing required key and an invalid enum value. The fact in the field is still the model’s answer.
Structured outputs in each tool
| Claude Code | Codex | Cursor | Grok | |
|---|---|---|---|---|
| A schema for the answer | --json-schema in print mode, and outputFormat in the Agent SDK |
codex exec --output-schema |
Not documented. --output-format json is a transcript wrapper |
API response_format json_schema. Not documented as a Build CLI flag |
| JSON that is not your schema | --output-format json is the print-mode wrapper |
--json is a JSONL event stream |
The wrapper’s result field is assistant text |
--output-format json is one JSON object at the end |
Claude Code
Print mode takes a schema on the flag. The CLI reference says Claude Code exits with an error on an invalid schema, and that it accepts the format keyword as an annotation without client-side validation:
claude -p --json-schema '{"type":"object","properties":{"project_name":{"type":"string"}},"required":["project_name"],"additionalProperties":false}' "Name this repo from package.json"
The Agent SDK is the same idea in a program. TypeScript passes outputFormat: { type: "json_schema", schema }. Python uses output_format. The agent can call tools first. The result then includes structured_output. The SDK validates the JSON and can ask again. If the retries fail, the result subtype is error_max_structured_output_retries. Zod and Pydantic are optional. See Get structured output from agents and the CLI reference.
The Claude API uses output_config.format with type: "json_schema", and strict tool use with strict: true. That page lists the model ids it supports. See Structured outputs.
OpenAI Codex
codex exec --output-schema asks for a final response that conforms to a JSON Schema. --json is a separate stream of events such as thread.started and turn.completed. It does not apply your schema.
Default codex exec is a read-only sandbox. The schema does not change that. See Non-interactive mode.
The API guide is the same contract outside the CLI: responses adhere to the supplied JSON Schema. See Structured Outputs.
Cursor
--output-format json with --print emits one JSON object when the run finishes. The result field is the assistant’s text, concatenated. stream-json is NDJSON events. Neither is a schema you wrote for the answer.
A schema constraint on that text is not on the output-format page. See Output format.
Grok
On the API, set response_format.type to json_schema and put the schema under response_format.json_schema. json_object means any well-formed JSON. text is the default.
additionalProperties defaults to false, and you set true explicitly when you want extra keys. Schemas written for Draft 2020-12 work best. Draft-07 is accepted. Tool-call arguments always conform to the tool’s input schema. The strict flag is implicitly true. The Grok 4.7 card lists structured outputs as supported. See Structured outputs.
Grok Build’s headless mode has --output-format values plain, json, and streaming-json. json means one JSON object at the end. That object is the CLI envelope, not a schema you passed. No --output-schema flag is on that page. See Headless and scripting.
Details checked against each vendor’s documentation in November 2026.
A real example
This is the schema from Codex’s non-interactive page, and the command that page runs with it. schema.json:
{
"type": "object",
"properties": {
"project_name": { "type": "string" },
"programming_languages": {
"type": "array",
"items": { "type": "string" }
}
},
"required": ["project_name", "programming_languages"],
"additionalProperties": false
}
codex exec "Extract project metadata" \
--output-schema ./schema.json \
-o ./project-metadata.json
The page’s sample final JSON is {"project_name":"Codex CLI","programming_languages":["Rust","TypeScript","Shell"]}. Your repo will fill the same two fields. It will not invent a third key, because additionalProperties is false.
When to use structured outputs
Use a schema when the next step is code that reads fields. A release note parser, a list of languages, a routing label with a fixed set of values. The Jev post’s department example is that case.
Use ordinary text when a person is reading the answer. A schema in that chat is extra machinery.
CLI Tools Cabinet has a JSON CLI for coding agents. The tutorial runs clitools search sound --json. That JSON is the tool’s output. Structured outputs are the other direction: the model’s own final answer.
Pitfalls
--output-format json in Cursor and in Grok Build, and codex exec --json, wrap the session. They do not apply a schema to the prose. If you parse result and expect project_name, you are reading the wrong object.
JSON mode asks for JSON. A schema also fixes the keys and the values you listed. The Jev post and OpenAI’s guide both make that split. An extra key, or "department": "other", is still valid JSON.
A schema match is not a correct answer. The field can be the wrong language, spelled in an allowed enum. Check it the way you check any other model output. Evals is one place that check lives. Tool calling is the related step, where the schema describes a function’s arguments instead of the final answer.
Related on flaviocopes.com
Related glossary entries
- Tool calling: Tool calling is when a model names a function and its arguments, and the app runs it. How Claude Code, Codex, Cursor and Grok Build take that step.
- Evals: An eval is a fixed prompt, a real agent run, and a check you can repeat. How Claude Code, Codex, Cursor and the Grok API score that run.
- Coding agent: A coding agent uses a model and tools to read a repo, edit files and run commands in a loop. How Claude Code, Codex, Cursor and Grok Build each do that job.
Want me to talk about your product? You can sponsor this site.