Structured Data Generation
Purpose and Scope
Structured data generation is the AI SDK Core workflow for asking a model to return data that fits a declared shape rather than free-form prose. The documentation frames the problem with common application tasks such as information extraction, classification, and synthetic data generation. These tasks need more than a natural-language answer: callers need fields, arrays, nested objects, and validation so downstream code can trust the result. The source page explains that providers may expose this capability through JSON modes or tools, but the SDK gives readers a provider-neutral way to describe and validate the desired structure.
Sources: content/docs/03-ai-sdk-core/10-generating-structured-data.mdx
The current documented API centers on generateText and streamText with an output configuration, specifically Output.object. That is an important shift in mental model: structured output is not a separate island from normal text generation, tool calling, or streaming. It is part of the same model-call flow and can be combined with tool execution in a single request. Because the schema also validates the result, developers get a single place to state both the desired model output and the runtime contract their application expects.
Sources: content/docs/03-ai-sdk-core/10-generating-structured-data.mdx
Relevant Source Files
content/docs/03-ai-sdk-core/10-generating-structured-data.mdx— Defines the reader-facing structured data guide, including when to use structured generation, supported schema styles,Output.object, raw provider response access, streaming partial outputs, and stream error handling.
Core Primitives
The main primitive is the output specification. A caller passes output: Output.object({ schema }) into a generation request, and the SDK uses that schema to steer the model response and validate the generated data. The source page explicitly names Zod schemas, Valibot schemas, and JSON schemas as supported ways to describe the object shape. This lets teams choose a schema system that matches their existing codebase while still using the same generation interface across providers and models.
Sources: content/docs/03-ai-sdk-core/10-generating-structured-data.mdx
A second primitive is the structured result itself. For a non-streaming request, the documented example destructures output from the result of generateText. The example schema describes a recipe object with a name, ingredients, and steps, showing that nested objects and arrays are expected use cases rather than edge cases. The SDK validates the generated object against the schema, so application code can treat the resulting value as the typed data product of the call rather than as text that still needs ad hoc parsing.
Sources: content/docs/03-ai-sdk-core/10-generating-structured-data.mdx
Non-Streaming Workflow
Use the non-streaming workflow when the application can wait for the complete object before rendering or processing it. In this path, the prompt describes the task, the model is selected normally, and the output object declares the schema. The result object also exposes the provider response when needed. The documentation calls out response.headers and response.body for cases where an integration needs provider-specific metadata, diagnostics, or raw response details beyond the validated structured output.
Sources: content/docs/03-ai-sdk-core/10-generating-structured-data.mdx
import { generateText, Output } from 'ai';
import { z } from 'zod';
const { output, response } = await generateText({
model,
output: Output.object({
schema: z.object({
recipe: z.object({
name: z.string(),
ingredients: z.array(
z.object({ name: z.string(), amount: z.string() }),
),
steps: z.array(z.string()),
}),
}),
}),
prompt: 'Generate a lasagna recipe.',
});
console.log(output.recipe.name);
console.log(response.headers);Structured output generation also participates in the SDK multi-turn execution model. The source page states that a structured output generation counts as a step, where each model call or tool execution is one step. This matters when a request combines output generation with tools, because the stop condition must leave room for all expected work. If stopWhen is too restrictive, a run that needs a tool result and a final structured object may stop before the object has been produced or validated.
Sources: content/docs/03-ai-sdk-core/10-generating-structured-data.mdx
Streaming Workflow
Use the streaming workflow when the final object may take long enough that an interactive interface should receive progress. The source page describes using streamText with the same output configuration, then consuming partialOutputStream as an async iterable. Each yielded value is a partial version of the structured response as it is generated. This design lets a page, terminal, or service update progressively without abandoning the same schema-driven validation model used by the non-streaming path.
Sources: content/docs/03-ai-sdk-core/10-generating-structured-data.mdx
import { streamText, Output } from 'ai';
import { z } from 'zod';
const { partialOutputStream } = streamText({
model,
output: Output.object({
schema: z.object({
recipe: z.object({
name: z.string(),
ingredients: z.array(
z.object({ name: z.string(), amount: z.string() }),
),
steps: z.array(z.string()),
}),
}),
}),
prompt: 'Generate a lasagna recipe.',
});
for await (const partialObject of partialOutputStream) {
console.log(partialObject);
}For client applications, the same documentation points readers to the useObject hook for consuming structured output on the client. The server side still defines the model, prompt, and schema, while the client side can focus on rendering the object as it arrives. This is especially useful for forms, dashboards, extraction previews, and generated configuration where partial fields can be shown before the final object is complete. The shared idea is that the schema remains the contract, even when delivery is incremental.
Sources: content/docs/03-ai-sdk-core/10-generating-structured-data.mdx
Error Handling and Operational Notes
Streaming changes how errors surface. The documentation states that streamText starts streaming immediately, so errors that occur during streaming become part of the stream rather than thrown exceptions. This prevents an already-open stream from crashing in the usual synchronous way, but it also means callers must plan for stream-level error handling. The documented answer is to provide an onError callback, which gives the application a clear place to log, transform, or render failures while the stream protocol continues to behave predictably.
Sources: content/docs/03-ai-sdk-core/10-generating-structured-data.mdx
The most important implementation decision is to treat schemas as application contracts, not just prompting hints. Models can produce incorrect or incomplete structured data, and the source page explicitly warns that generated data still needs validation. A good schema should be specific enough to reject unusable output while still allowing the model to complete the task. For example, required nested fields make sense for a recipe application, while optional fields may be better for extraction tasks where the source text may not contain every value.
Sources: content/docs/03-ai-sdk-core/10-generating-structured-data.mdx
Compact API Reference
| Concern | Public surface | Behavior |
|---|---|---|
| Non-streaming object generation | generateText with output: Output.object({ schema }) | Returns a validated output object after the model finishes. |
| Structured streaming | streamText with output: Output.object({ schema }) | Exposes partialOutputStream for incremental structured values. |
| Schema definition | Zod, Valibot, or JSON Schema | Describes and validates the object shape. |
| Provider diagnostics | result.response.headers and result.response.body | Gives access to raw provider response metadata and body content. |
| Stream errors | onError callback | Handles errors that occur after streaming has started. |
| UI consumption | useObject | Consumes structured output in client-facing UI flows. |
Next Steps
Start with the non-streaming pattern when building a new extraction, classification, or generation task, because it is easier to debug a complete validated object. Move to streaming once response latency affects the user experience, and keep the same schema so both paths remain compatible. If the request also uses tools, review the multi-step stopping configuration before production use. Related pages to read next are Generating Text and Streaming, Tools and Tool Calling, Stream Protocol, Transport, and Metadata, and UI Hooks and Transports Reference.