Structured Output from LLMs
A practical guide to structured LLM output, including JSON responses, schemas, validation, prompting techniques, error handling, and how to build reliable applications around model-generated data.
Large language models are designed to generate natural language, but many real applications need something much more predictable. A chatbot may need to return a list of products, a web application may need structured form data, and an API integration may need a JSON object that can be processed automatically by a backend. If the model is allowed to answer in completely free-form text, turning that response into reliable application data can become difficult.
Structured output is the approach of instructing an LLM to return data in a predefined format. Instead of receiving an unpredictable paragraph, the application can request an object with specific fields, arrays, data types, and constraints. The result can then be parsed, validated, stored, or passed to another part of the system.
This makes structured output one of the most important techniques for building reliable LLM-powered applications. It connects the flexibility of natural-language generation with the strict requirements of traditional software systems.
What Is Structured Output?
Structured output is an LLM response that follows a predefined data structure rather than an arbitrary natural-language format. The structure can be as simple as a JSON object with a few fields or as complex as a nested schema containing arrays, objects, numbers, booleans, and enumerated values.
For example, instead of asking an AI model to classify a support message and receiving a sentence such as "This appears to be a billing problem," an application can request an object like this:
{
"category": "billing",
"priority": "high",
"requiresHuman": true
}The second response is much easier for software to consume. The backend can read the category, check the priority, and determine whether the request should be sent to a human agent without having to interpret natural-language text.
Why Structured Output Matters
Traditional software relies heavily on predictable data structures. A database expects columns with known types, an API expects specific fields, and a frontend component expects data in a particular shape. LLMs, however, naturally produce flexible text. Structured output provides a bridge between these two worlds.
- Applications can parse model responses more reliably.
- Backend systems can validate generated data before using it.
- Frontend components can render predictable fields.
- Database records can be created from model responses.
- Different models can follow the same application-level schema.
- Errors become easier to detect and handle.
- LLM output can be passed safely to other software components.
Free-Form Text vs Structured Output
Consider an application that extracts information from a customer message. With free-form generation, the model might return different wording every time. One response could contain a paragraph, another could use bullet points, and another could omit a field entirely.
A structured response defines exactly what the application expects. For example, a customer extraction schema might contain a customer name, email address, order number, issue category, and sentiment.
| Approach | Typical response | Main problem |
|---|---|---|
| Free-form text | The customer appears to have a problem with order 12345. | The application must interpret the text. |
| Prompted JSON | {"orderId":"12345","category":"delivery"} | The model may still produce invalid or unexpected JSON. |
| Schema-constrained output | A response matching a predefined schema | Much easier to parse and validate. |
JSON as a Common Structured Format
JSON is one of the most common formats for structured LLM output because it is supported by virtually every modern programming language and is already widely used in APIs. JavaScript and TypeScript applications can parse JSON directly, while backend languages such as Python, Go, Java, and C# also provide mature JSON libraries.
A simple JSON response might look like this:
{
"title": "Introduction to TypeScript",
"difficulty": "beginner",
"tags": [
"typescript",
"javascript",
"programming"
]
}The important property is not simply that the response is JSON. The application also needs to know what fields are expected, which values are valid, and what data types each field should contain.
Structured Output Is More Than JSON
It is useful to distinguish JSON from structured output. JSON is a serialization format, while structured output describes the requirement that a model produce data conforming to a particular structure.
A model can be asked to return JSON without being given a strict schema. In that case, it might technically produce valid JSON while still returning the wrong fields, incorrect types, unexpected values, or missing information.
For example, an application might expect an integer called "age":
{
"age": 32
}But a loosely instructed model could produce:
{
"age": "thirty-two"
}The second object is valid JSON, but it does not satisfy the application's expected type. This is why schema validation and constrained generation are important.
Using a JSON Schema
A JSON Schema describes the structure and constraints that generated data should follow. It can define required properties, data types, arrays, nested objects, enumerated values, and other restrictions.
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"age": {
"type": "integer"
},
"role": {
"type": "string",
"enum": ["developer", "designer", "manager"]
}
},
"required": ["name", "age", "role"],
"additionalProperties": false
}This schema tells the application what a valid response should look like. The model should return an object containing name, age, and role, while role must be one of the allowed values.
Prompting for Structured Output
One of the simplest approaches is to explicitly describe the required format in the prompt. This works particularly well for simple tasks and APIs that do not provide native structured-output features.
Extract the following information from the text.
Return JSON with exactly these fields:
- name: string
- email: string
- company: string
- isCustomer: boolean
Do not include any additional fields.
Text:
John works at Example Corp and can be contacted at john@example.com.Clear instructions reduce ambiguity, but prompt-only formatting does not provide the same guarantees as an API feature that constrains the model's output. The model can still make mistakes, especially with complicated schemas or unusual input.
Schema-Constrained Generation
Modern LLM APIs can provide mechanisms that make the model follow a specified schema more strictly. Depending on the provider, these features may be called structured outputs, JSON schema output, constrained decoding, or similar terms.
Instead of relying entirely on the model to remember formatting instructions, the application sends a machine-readable schema alongside the request. The model generation system can then constrain the possible output to make it compatible with that schema.
This is generally more reliable than simply writing "return valid JSON" in a prompt. However, developers should still validate the final response because schema compliance does not guarantee that the generated information is factually correct.
Structured Output Does Not Guarantee Correct Information
Suppose a schema requires a product price to be a number. The model could correctly return a numeric value while still inventing the price. The JSON structure is valid, but the data is wrong.
This distinction is important when designing production systems. Structured output solves a data-format problem. It does not automatically solve hallucinations, outdated information, reasoning errors, or incorrect extraction.
Validating LLM Output
Applications should validate structured responses before using them. Validation checks whether the returned data satisfies the application's requirements rather than assuming that the model always followed the instructions correctly.
In TypeScript applications, schema-validation libraries such as Zod are commonly used to define expected data and validate parsed responses.
import { z } from "zod";
const UserSchema = z.object({
name: z.string(),
age: z.number().int(),
role: z.enum(["developer", "designer", "manager"]),
});
const result = UserSchema.safeParse(modelResponse);
if (!result.success) {
console.error("Invalid model output", result.error);
} else {
const user = result.data;
console.log(user.name);
}Runtime validation is especially important because TypeScript types disappear when the application is running. A value coming from an external API is not automatically trustworthy just because a TypeScript interface says it should have a particular shape.
TypeScript Types Are Not Runtime Validation
A common mistake is to cast an LLM response directly to a TypeScript type:
const user = modelResponse as User;
console.log(user.name);This only tells the TypeScript compiler to trust the value. It does not check whether the object actually contains the expected fields or types.
For data generated by an external model, runtime validation is safer. A schema can verify the response before the application performs important operations with it.
Handling Optional Fields
Schemas should distinguish between required and optional information. If a field is not always available in the source data, making it mandatory can cause unnecessary failures.
const ProductSchema = z.object({
name: z.string(),
price: z.number(),
description: z.string().optional(),
});The correct choice depends on the application. If a missing field represents an invalid result, make it required. If the information genuinely may not exist, represent that possibility explicitly.
Enums Make Classification More Reliable
Classification tasks are a good example of where structured output provides significant value. Instead of allowing the model to invent arbitrary category names, the schema can restrict the result to a predefined set.
{
"type": "object",
"properties": {
"sentiment": {
"type": "string",
"enum": ["positive", "neutral", "negative"]
}
},
"required": ["sentiment"]
}This prevents variations such as "very positive", "good", "happy", and "positive sentiment" from becoming separate values in the application. The backend receives one of the predefined categories instead.
Nested Structured Data
Structured output can represent much more than a flat object. Complex applications may need nested objects and arrays.
{
"customer": {
"name": "Alex",
"email": "alex@example.com"
},
"order": {
"id": "ORD-1001",
"items": [
{
"name": "Keyboard",
"quantity": 1
},
{
"name": "Mouse",
"quantity": 2
}
]
}
}Nested schemas are useful for document extraction, product analysis, invoices, research results, content generation, and many other tasks. However, complex schemas also increase the chance of implementation mistakes, so they should be kept as simple as the application allows.
Structured Output for Data Extraction
One of the most useful applications is extracting structured information from unstructured text. Users may provide emails, support tickets, documents, descriptions, or messages that contain useful information in natural language.
The LLM can transform that text into a predictable object that the backend can process. For example, an application could extract an invoice into a structure containing the supplier, invoice number, date, currency, total, and line items.
- Email and support-ticket classification
- Invoice and receipt extraction
- Resume parsing
- Product information extraction
- Document metadata extraction
- Entity extraction
- Content categorization
- Survey and feedback analysis
Structured Output for Content Generation
Structured output is also useful when an LLM generates content that will be displayed by an application. For example, an AI writing tool could request a title, summary, introduction, sections, tags, and estimated reading time as separate fields.
{
"title": "Understanding HTTP Status Codes",
"summary": "A practical introduction to HTTP response codes.",
"tags": ["http", "web", "api"],
"sections": [
{
"heading": "What Are Status Codes?",
"content": "..."
},
{
"heading": "Common Status Codes",
"content": "..."
}
]
}The frontend can then render each section independently instead of trying to parse a large block of generated Markdown or HTML.
Structured Output vs Function Calling
Structured output and function calling are closely related but solve different problems. Structured output is primarily about the shape of the model's response. Function calling allows the model to request that an application execute a specific function or tool with structured arguments.
| Feature | Main purpose | Example |
|---|---|---|
| Structured output | Return data in a predefined format | Extract a customer's name and email. |
| Function calling | Request an application action | Call getWeather with a city argument. |
| Free-form output | Generate natural language | Explain how an API works. |
The two approaches can also be combined. An application might use function calling to invoke a search tool and then use structured output to organize the final result for the frontend.
Structured Output vs JSON Mode
JSON mode generally means that the model is instructed or constrained to produce valid JSON. Structured output goes a step further by defining what that JSON should contain and how it should be shaped.
| Capability | JSON mode | Schema-based structured output |
|---|---|---|
| Valid JSON | Yes | Yes |
| Specific required fields | Not necessarily | Yes |
| Specific data types | Not necessarily | Yes |
| Restricted enum values | Not necessarily | Yes |
| Predictable application shape | Limited | Much stronger |
The exact capabilities depend on the LLM provider and API. Developers should check the provider's current documentation rather than assuming that every API implements JSON mode and structured outputs in the same way.
Designing a Good Output Schema
A good schema should describe exactly what the application needs and nothing more. Overly complicated schemas make prompts harder to maintain and can make model responses more difficult to debug.
- Use descriptive property names.
- Choose appropriate data types.
- Use enums when the allowed values are known.
- Mark genuinely required fields as required.
- Represent optional information explicitly.
- Avoid unnecessary nesting.
- Keep the schema aligned with the application's actual data model.
- Validate the result before using it.
Keep Schemas Stable
If structured output is consumed by multiple parts of an application, changing the schema can have consequences beyond the LLM request itself. A frontend component, database model, analytics pipeline, or external integration may depend on specific fields.
Treat important LLM schemas similarly to API contracts. When making changes, consider backward compatibility, migration requirements, and how existing consumers will handle the new response.
Error Handling
Production applications should assume that an LLM request can fail. Network problems, provider errors, rate limits, invalid input, content-policy restrictions, incomplete responses, and unexpected model behavior can all occur.
A robust pipeline separates these failure cases. For example, a backend can distinguish between a failed API request and a response that was received but failed application-level validation.
const response = await generateStructuredResponse(input);
if (!response.ok) {
// Provider or network error
return { error: "AI request failed" };
}
const parsed = UserSchema.safeParse(response.data);
if (!parsed.success) {
// Unexpected application data
return { error: "Invalid AI response" };
}
return parsed.data;Retries and Validation
Retries can be useful when an LLM request fails because of a temporary provider or network error. However, blindly retrying every invalid response is not always appropriate. Validation failures may indicate a problem with the prompt, schema, input data, or model behavior.
A better strategy is to classify errors before retrying. Temporary infrastructure errors may be retried with backoff, while deterministic application errors should usually be logged and investigated rather than retried indefinitely.
Structured Output and Streaming
Streaming LLM responses introduces additional considerations. When text is delivered incrementally, the application may receive incomplete JSON or partial fields before the model finishes generating the response.
For simple user-facing text, streaming is straightforward because partial text can be displayed immediately. Structured data is different because an incomplete object may not be valid or safe to consume.
Applications that stream structured responses should therefore use provider-supported structured streaming mechanisms when available, or wait until the complete response has been received and validated before performing operations that require the full object.
Security Considerations
Structured output can improve reliability, but it does not make LLM-generated data automatically safe. Generated fields may eventually be inserted into databases, displayed in interfaces, passed to other services, or used as arguments to application logic.
Treat model output as untrusted external data. Validate types and allowed values, apply authorization checks independently, sanitize content where appropriate, and never allow an LLM response to bypass normal application security controls.
Structured Output Does Not Replace Business Logic
An LLM should generally determine or extract information, while deterministic application code should enforce critical business rules. For example, an AI system could classify a refund request as eligible, but the backend should independently verify the customer's order, refund limits, account status, and authorization.
This separation makes systems safer and easier to reason about. The model handles tasks where language understanding is useful, while traditional code remains responsible for rules that must be deterministic.
Common Mistakes
- Assuming valid JSON means correct data.
- Using TypeScript type assertions instead of runtime validation.
- Creating a schema with unnecessary fields.
- Allowing arbitrary strings when a fixed enum would be better.
- Treating model output as trusted application input.
- Using an LLM to enforce authorization or financial rules.
- Retrying every validation failure without investigating the cause.
- Depending on provider-specific behavior without checking current API documentation.
- Making large schema changes without considering existing consumers.
A Reliable Structured Output Pipeline
A production LLM application can treat structured generation as one stage in a larger pipeline. The model receives a clear task and schema, generates the response, and the application validates the result before passing it to business logic.
User input
↓
Prompt + structured schema
↓
LLM API
↓
Generated structured response
↓
JSON parsing
↓
Runtime validation
↓
Business rules
↓
Database / API / UIThis architecture keeps the boundary between probabilistic AI behavior and deterministic software logic clear. The model produces a candidate result, while the application decides whether that result is acceptable and what actions are allowed.
Testing Structured LLM Responses
Structured-output systems should be tested with more than a few normal examples. Real users provide incomplete, ambiguous, malformed, multilingual, and adversarial input, and the model may behave differently depending on the input.
- Test empty and very short inputs.
- Test incomplete information.
- Test contradictory information.
- Test unusually long inputs.
- Test different languages when multilingual input is supported.
- Test values outside expected ranges.
- Test malicious or instruction-like input inside source documents.
- Test provider errors and timeouts.
- Test invalid or incomplete model responses.
For important applications, maintain a collection of representative test cases and run them whenever prompts, schemas, models, or application logic change. This helps detect regressions that may not be visible from a single manual test.
When Should You Use Structured Output?
Structured output is particularly valuable whenever the next step in the application expects data rather than prose. If the model's answer is going directly to a human and natural language is the desired result, a strict schema may provide little benefit.
| Use case | Structured output value |
|---|---|
| Data extraction | Very high |
| Classification | Very high |
| API integrations | Very high |
| Database record generation | High |
| UI component generation | High |
| Agent tool results | High |
| Creative writing | Usually low |
| General conversational answers | Usually low |
Best Practices for Structured LLM Output
- Define the required data structure before writing the prompt.
- Prefer provider-supported structured-output features when available.
- Use JSON Schema or an equivalent schema definition for predictable data.
- Keep schemas as simple as possible.
- Use enums for values with a known finite set.
- Validate every important response at runtime.
- Treat model output as untrusted external data.
- Keep business-critical rules in deterministic application code.
- Separate provider errors from validation errors.
- Test structured generation with realistic and adversarial inputs.
- Monitor validation failures in production.
- Version important schemas when they are shared across application components.
Frequently Asked Questions
What is structured output in an LLM?
Structured output is a model response that follows a predefined format or schema, such as a JSON object with specific fields and data types. It allows software applications to consume LLM responses more predictably than free-form text.
Is structured output the same as JSON mode?
No. JSON mode generally focuses on producing valid JSON, while structured output can additionally define the exact fields, types, and allowed values that the response should contain. The exact capabilities depend on the LLM provider.
Does structured output prevent AI hallucinations?
No. Structured output controls the format of the response, not whether the information is factually correct. A model can produce perfectly valid structured data containing incorrect information, so important results should still be validated and, when necessary, verified against trusted data.
Should I validate structured LLM responses?
Yes. Runtime validation is recommended even when an API provides schema-constrained generation. Validation provides an application-level safety boundary and helps detect unexpected responses, integration problems, and invalid data.
Is structured output better than function calling?
They solve different problems. Structured output is mainly used when an application needs the model to return data in a predictable shape. Function calling is used when the model needs to request that an application execute a specific tool or function with structured arguments. They can also be used together.
Helpful AI Tools
When working with structured LLM responses, developer tools for JSON formatting, JSON validation, schema inspection, prompt testing, and API debugging can make development easier. These tools are useful for checking generated data before integrating it into application code and for troubleshooting malformed responses.
Conclusion
Structured output makes LLMs much easier to integrate with traditional software. Instead of treating every model response as an unpredictable block of text, developers can define a schema that describes the data their application actually needs. JSON schemas, constrained generation, runtime validation, enums, and clear prompts can significantly improve reliability.
The key limitation is that structured output guarantees structure, not truth. A reliable AI application therefore combines schema-constrained generation with runtime validation, deterministic business logic, security checks, error handling, and thorough testing. Used this way, structured output provides a practical foundation for building LLM applications that can interact safely with APIs, databases, interfaces, and other software systems.