Ctrl + K
AI20 min read

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.

Published: 2026-09-14

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.

ApproachTypical responseMain problem
Free-form textThe 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 outputA response matching a predefined schemaMuch 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

⚠️ A response can be perfectly valid according to a schema and still contain incorrect information. Structured output controls the shape of the response, not the truthfulness of its contents.

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.

FeatureMain purposeExample
Structured outputReturn data in a predefined formatExtract a customer's name and email.
Function callingRequest an application actionCall getWeather with a city argument.
Free-form outputGenerate natural languageExplain 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.

CapabilityJSON modeSchema-based structured output
Valid JSONYesYes
Specific required fieldsNot necessarilyYes
Specific data typesNot necessarilyYes
Restricted enum valuesNot necessarilyYes
Predictable application shapeLimitedMuch 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.
💡 Design the schema from the application's requirements first, then write the prompt around that schema. Do not start by asking the model for arbitrary JSON and build your data model around whatever it happens to return.

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.

⚠️ Do not treat schema validation as authorization. A model can return a perfectly valid field such as userId, action, or amount while still being unauthorized to perform the corresponding operation.

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 / UI

This 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 caseStructured output value
Data extractionVery high
ClassificationVery high
API integrationsVery high
Database record generationHigh
UI component generationHigh
Agent tool resultsHigh
Creative writingUsually low
General conversational answersUsually 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.
💡 The strongest architecture is usually not "make the LLM always return perfect data." Instead, design the system so that imperfect model output is detected before it can cause an incorrect application action.

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.

Found an issue?

Found an error, outdated information, or something missing from this article? Let me know through the Contact page.

Your feedback helps improve our articles and keep them accurate and useful.