You can configure Gemini models to generate responses that adhere to a provided JSON Schema. This capability guarantees predictable and parsable results, ensures format and type-safety, enables the programmatic detection of refusals, and simplifies prompting.
Using structured outputs is ideal for a wide range of applications:
- Data extraction: Pull specific information from unstructured text, like extracting names, dates, and amounts from an invoice.
- Structured classification: Classify text into predefined categories and assign structured labels, such as categorizing customer feedback by sentiment and topic.
- Agentic workflows: Generate structured data that can be used to call other tools or APIs, like creating a character sheet for a game or filling out a form.
In addition to supporting JSON Schema in the REST API, the Google GenAI SDKs for Python and JavaScript also make it easy to define object schemas using Pydantic and Zod, respectively. The example below demonstrates how to extract information from unstructured text that conforms to a schema defined in code.
This example showcases anyOf for conditional schemas and enum for classification, allowing the output structure to vary based on the content.
Python
from google import genai
from pydantic import BaseModel, Field
from typing import Union, Literal
class SpamDetails(BaseModel):
reason: str = Field(description="The reason why the content is considered spam.")
spam_type: Literal["phishing", "scam", "unsolicited promotion", "other"] = Field(description="The type of spam.")
class NotSpamDetails(BaseModel):
summary: str = Field(description="A brief summary of the content.")
is_safe: bool = Field(description="Whether the content is safe for all audiences.")
class ModerationResult(BaseModel):
decision: Union[SpamDetails, NotSpamDetails]
client = genai.Client()
prompt = """
Please moderate the following content and provide a decision.
Content: 'Congratulations! You''ve won a free cruise to the Bahamas. Click here to claim your prize: www.definitely-not-a-scam.com'
"""
response = client.models.generate_content(
model="gemini-2.5-flash",
contents=prompt,
config={
"response_mime_type": "application/json",
"response_json_schema": ModerationResult.model_json_schema(),
},
)
result = ModerationResult.model_validate_json(response.text)
print(result)
JavaScript
import { GoogleGenAI } from "@google/genai";
import { z } from "zod";
import { zodToJsonSchema } from "zod-to-json-schema";
const spamDetailsSchema = z.object({
reason: z.string().describe("The reason why the content is considered spam."),
spam_type: z.enum(["phishing", "scam", "unsolicited promotion", "other"]).describe("The type of spam."),
});
const notSpamDetailsSchema = z.object({
summary: z.string().describe("A brief summary of the content."),
is_safe: z.boolean().describe("Whether the content is safe for all audiences."),
});
const moderationResultSchema = z.object({
decision: z.union([spamDetailsSchema, notSpamDetailsSchema]),
});
const ai = new GoogleGenAI({});
const prompt = `
Please moderate the following content and provide a decision.
Content: 'Congratulations! You''ve won a free cruise to the Bahamas. Click here to claim your prize: www.definitely-not-a-scam.com'
`;
const response = await ai.models.generateContent({
model: "gemini-2.5-flash",
contents: prompt,
config: {
responseMimeType: "application/json",
responseJsonSchema: zodToJsonSchema(moderationResultSchema),
},
});
const result = moderationResultSchema.parse(JSON.parse(response.text));
console.log(result);
Go
package main
import (
"context"
"fmt"
"log"
"google.golang.org/genai"
)
func main() {
ctx := context.Background()
client, err := genai.NewClient(ctx, nil)
if err != nil {
log.Fatal(err)
}
prompt := `
Please moderate the following content and provide a decision.
Content: 'Congratulations! You''ve won a free cruise to the Bahamas. Click here to claim your prize: www.definitely-not-a-scam.com'
`
config := &genai.GenerateContentConfig{
ResponseMIMEType: "application/json",
ResponseJsonSchema: map[string]any{
"type": "object",
"properties": map[string]any{
"decision": map[string]any{
"anyOf": []map[string]any{
{
"type": "object",
"title": "SpamDetails",
"description": "Details for content classified as spam.",
"properties": map[string]any{
"reason": map[string]any{
"type": "string",
"description": "The reason why the content is considered spam.",
},
"spam_type": map[string]any{
"type": "string",
"enum": []string{"phishing", "scam", "unsolicited promotion", "other"},
"description": "The type of spam.",
},
},
"required": []string{"reason", "spam_type"},
},
{
"type": "object",
"title": "NotSpamDetails",
"description": "Details for content classified as not spam.",
"properties": map[string]any{
"summary": map[string]any{
"type": "string",
"description": "A brief summary of the content.",
},
"is_safe": map[string]any{
"type": "boolean",
"description": "Whether the content is safe for all audiences.",
},
},
"required": []string{"summary", "is_safe"},
},
},
},
},
"required": []string{"decision"},
},
}
result, err := client.Models.GenerateContent(
ctx,
"gemini-2.5-flash",
genai.Text(prompt),
config,
)
if err != nil {
log.Fatal(err)
}
fmt.Println(result.Text())
}
REST
curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-H 'Content-Type: application/json' \
-X POST \
-d '{
"contents": [{
"parts":[
{ "text": "Please moderate the following content and provide a decision.\nContent: ''Congratulations! You have won a free cruise to the Bahamas. Click here to claim your prize: www.definitely-not-a-scam.com''" }
]
}],
"generationConfig": {
"responseMimeType": "application/json",
"responseJsonSchema": {
"type": "object",
"properties": {
"decision": {
"anyOf": [
{
"type": "object",
"title": "SpamDetails",
"description": "Details for content classified as spam.",
"properties": {
"reason": { "type": "string", "description": "The reason why the content is considered spam." },
"spam_type": { "type": "string", "enum": ["phishing", "scam", "unsolicited promotion", "other"], "description": "The type of spam." }
},
"required": ["reason", "spam_type"]
},
{
"type": "object",
"title": "NotSpamDetails",
"description": "Details for content classified as not spam.",
"properties": {
"summary": { "type": "string", "description": "A brief summary of the content." },
"is_safe": { "type": "boolean", "description": "Whether the content is safe for all audiences." }
},
"required": ["summary", "is_safe"]
}
]
}
},
"required": ["decision"]
}
}
}'
Example Response:
{
"decision": {
"reason": "The content is an unsolicited prize notification attempting to trick the user into clicking a suspicious link.",
"spam_type": "scam"
}
}
Streaming
You can stream structured outputs, which allows you to start processing the response as it's being generated, without having to wait for the entire output to be complete. This can improve the perceived performance of your application.
The streamed chunks will be valid partial JSON strings, which can be concatenated to form the final, complete JSON object.
Python
from google import genai
from pydantic import BaseModel, Field
from typing import Literal
class Feedback(BaseModel):
sentiment: Literal["positive", "neutral", "negative"]
summary: str
client = genai.Client()
prompt = "The new UI is incredibly intuitive and visually appealing. Great job. Add a very long summary to test streaming!"
response_stream = client.models.generate_content_stream(
model="gemini-2.5-flash",
contents=prompt,
config={
"response_mime_type": "application/json",
"response_json_schema": Feedback.model_json_schema(),
},
)
for chunk in response_stream:
print(chunk.candidates[0].content.parts[0].text)
JavaScript
import { GoogleGenAI } from "@google/genai";
import { z } from "zod";
import { zodToJsonSchema } from "zod-to-json-schema";
const ai = new GoogleGenAI({});
const prompt = "The new UI is incredibly intuitive and visually appealing. Great job! Add a very long summary to test streaming!";
const feedbackSchema = z.object({
sentiment: z.enum(["positive", "neutral", "negative"]),
summary: z.string(),
});
const stream = await ai.models.generateContentStream({
model: "gemini-2.5-flash",
contents: prompt,
config: {
responseMimeType: "application/json",
responseJsonSchema: zodToJsonSchema(feedbackSchema),
},
});
for await (const chunk of stream) {
console.log(chunk.candidates[0].content.parts[0].text)
}
JSON schema support
To generate a JSON object, set the response_mime_type in the generation configuration to application/json and provide a response_json_schema. The schema must be a valid JSON Schema that describes the desired output format.
The model will then generate a response that is a syntactically valid JSON string matching the provided schema. When using structured outputs, the model will produce outputs in the same order as the keys in the schema.
Gemini's structured output mode supports a subset of the JSON Schema specification.
The following values of type are supported:
string: For text.number: For floating-point numbers.integer: For whole numbers.boolean: For true/false values.object: For structured data with key-value pairs.array: For lists of items.null: To allow a property to be null, include"null"in the type array (e.g.,{"type": ["string", "null"]}).
These descriptive properties help guide the model:
title: A short description of a property.description: A longer and more detailed description of a property.
Type-specific properties
For object values:
properties: An object where each key is a property name and each value is a schema for that property.required: An array of strings, listing which properties are mandatory.additionalProperties: Controls whether properties not listed inpropertiesare allowed. Can be a boolean or a schema.
For string values:
enum: Lists a specific set of possible strings for classification tasks.format: Specifies a syntax for the string, such asdate-time,date,time.
For number and integer values:
enum: Lists a specific set of possible numeric values.minimum: The minimum inclusive value.maximum: The maximum inclusive value.
For array values:
items: Defines the schema for all items in the array.prefixItems: Defines a list of schemas for the first N items, allowing for tuple-like structures.minItems: The minimum number of items in the array.maxItems: The maximum number of items in the array.
Model support
The following models support structured output:
| Model | Structured Outputs |
|---|---|
| Gemini 2.5 Pro | ✔️ |
| Gemini 2.5 Flash | ✔️ |
| Gemini 2.5 Flash-Lite | ✔️ |
| Gemini 2.0 Flash | ✔️* |
| Gemini 2.0 Flash-Lite | ✔️* |
* Note that Gemini 2.0 requires an explicit propertyOrdering list within the JSON input to define the preferred structure. You can find an example in this cookbook.
Structured outputs vs. function calling
Both structured outputs and function calling use JSON schemas, but they serve different purposes:
| Feature | Primary Use Case |
|---|---|
| Structured Outputs | Formatting the final response to the user. Use this when you want the model's answer to be in a specific format (e.g., extracting data from a document to save to a database). |
| Function Calling | Taking action during the conversation. Use this when the model needs to ask you to perform a task (e.g., "get current weather") before it can provide a final answer. |
Best practices
- Clear descriptions: Use the
descriptionfield in your schema to provide clear instructions to the model about what each property represents. This is crucial for guiding the model's output. - Strong typing: Use specific types (
integer,string,enum) whenever possible. If a parameter has a limited set of valid values, use anenum. - Prompt engineering: Clearly state in your prompt what you want the model to do. For example, "Extract the following information from the text..." or "Classify this feedback according to the provided schema...".
- Validation: While structured output guarantees syntactically correct JSON, it does not guarantee the values are semantically correct. Always validate the final output in your application code before using it.
- Error handling: Implement robust error handling in your application to gracefully manage cases where the model's output, while schema-compliant, may not meet your business logic requirements.
Limitations
- Schema subset: Not all features of the JSON Schema specification are supported. The model ignores unsupported properties.
- Schema complexity: The API may reject very large or deeply nested schemas. If you encounter errors, try simplifying your schema by shortening property names, reducing nesting, or limiting the number of constraints.