By default, Gemini generates unstructured text, but you can constrain the model to respond with structured output instead – either JSON or a value from an enum. This structured output feature is particularly useful when you need to extract information from unstructured data and then process it for consumption by an application. For example, you could use the feature to extract standardized information from resumes and then build a database out of the info. Or you could extract ingredients from recipes and display a link to a grocery website for each ingredient.
This guide shows you how to generate structured output using the Gemini API.
Generating JSON
There are two ways to generate JSON using the Gemini API:
- Configure a schema on the model
- Provide a schema in a text prompt
Configuring a schema on the model is the recommended way to generate JSON, because it constrains the model to output JSON.
Configuring a schema
To constrain the model to generate JSON, configure a responseSchema
. The model
will then respond to any prompt with JSON-formatted output.
Python
from google import genai
from pydantic import BaseModel
class Recipe(BaseModel):
recipe_name: str
ingredients: list[str]
client = genai.Client(api_key="GOOGLE_API_KEY")
response = client.models.generate_content(
model="gemini-2.0-flash",
contents="List a few popular cookie recipes, and include the amounts of ingredients.",
config={
"response_mime_type": "application/json",
"response_schema": list[Recipe],
},
)
# Use the response as a JSON string.
print(response.text)
# Use instantiated objects.
my_recipes: list[Recipe] = response.parsed
JavaScript
import { GoogleGenAI, Type } from "@google/genai";
const ai = new GoogleGenAI({ "GOOGLE_API_KEY" });
async function main() {
const response = await ai.models.generateContent({
model: "gemini-2.0-flash",
contents:
"List a few popular cookie recipes, and include the amounts of ingredients.",
config: {
responseMimeType: "application/json",
responseSchema: {
type: Type.ARRAY,
items: {
type: Type.OBJECT,
properties: {
recipeName: {
type: Type.STRING,
},
ingredients: {
type: Type.ARRAY,
items: {
type: Type.STRING,
},
},
},
propertyOrdering: ["recipeName", "ingredients"],
},
},
},
});
console.log(response.text);
}
main();
Go
package main
import (
"context"
"fmt"
"log"
"google.golang.org/genai"
)
func main() {
ctx := context.Background()
client, err := genai.NewClient(ctx, &genai.ClientConfig{
APIKey: "GOOGLE_API_KEY",
Backend: genai.BackendGeminiAPI,
})
if err != nil {
log.Fatal(err)
}
config := &genai.GenerateContentConfig{
ResponseMIMEType: "application/json",
ResponseSchema: &genai.Schema{
Type: genai.TypeArray,
Items: &genai.Schema{
Type: genai.TypeObject,
Properties: map[string]*genai.Schema{
"recipeName": {Type: genai.TypeString},
"ingredients": {
Type: genai.TypeArray,
Items: &genai.Schema{Type: genai.TypeString},
},
},
PropertyOrdering: []string{"recipeName", "ingredients"},
},
},
}
result, err := client.Models.GenerateContent(
ctx,
"gemini-2.0-flash",
genai.Text("List a few popular cookie recipes, and include the amounts of ingredients."),
config,
)
if err != nil {
log.Fatal(err)
}
fmt.Println(result.Text())
}
REST
curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=$GOOGLE_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"contents": [{
"parts":[
{ "text": "List a few popular cookie recipes, and include the amounts of ingredients." }
]
}],
"generationConfig": {
"responseMimeType": "application/json",
"responseSchema": {
"type": "ARRAY",
"items": {
"type": "OBJECT",
"properties": {
"recipeName": { "type": "STRING" },
"ingredients": {
"type": "ARRAY",
"items": { "type": "STRING" }
}
},
"propertyOrdering": ["recipeName", "ingredients"]
}
}
}
}' 2> /dev/null | head
The output might look like this:
[
{
"recipeName": "Chocolate Chip Cookies",
"ingredients": [
"1 cup (2 sticks) unsalted butter, softened",
"3/4 cup granulated sugar",
"3/4 cup packed brown sugar",
"1 teaspoon vanilla extract",
"2 large eggs",
"2 1/4 cups all-purpose flour",
"1 teaspoon baking soda",
"1 teaspoon salt",
"2 cups chocolate chips"
]
},
...
]
Providing a schema in a text prompt
Instead of configuring a schema, you can supply a schema as natural language or pseudo-code in a text prompt. This method is not recommended, because it might produce lower quality output, and because the model is not constrained to follow the schema.
Here's a generic example of a schema provided in a text prompt:
List a few popular cookie recipes, and include the amounts of ingredients.
Produce JSON matching this specification:
Recipe = { "recipeName": string, "ingredients": array<string> }
Return: array<Recipe>
Since the model gets the schema from text in the prompt, you might have some flexibility in how you represent the schema. But when you supply a schema inline like this, the model is not actually constrained to return JSON. For a more deterministic, higher quality response, configure a schema on the model, and don't duplicate the schema in the text prompt.
JSON schemas
When you configure the model to return a JSON response, you use a Schema
object to define the shape of the JSON data. The Schema
represents a select
subset of the
OpenAPI 3.0 Schema object,
and also adds a propertyOrdering
field.
Here's a pseudo-JSON representation of all the Schema
fields:
{
"type": enum (Type),
"format": string,
"description": string,
"nullable": boolean,
"enum": [
string
],
"maxItems": integer,
"minItems": integer,
"properties": {
string: {
object (Schema)
},
...
},
"required": [
string
],
"propertyOrdering": [
string
],
"items": {
object (Schema)
}
}
The Type
of the schema must be one of the OpenAPI
Data Types, or a union of
those types (using anyOf
). Only a subset of fields is valid for each Type
.
The following list maps each Type
to a subset of the fields that are valid for
that type:
string
->enum
,format
,nullable
integer
->format
,minimum
,maximum
,enum
,nullable
number
->format
,minimum
,maximum
,enum
,nullable
boolean
->nullable
array
->minItems
,maxItems
,items
,nullable
object
->properties
,required
,propertyOrdering
,nullable
Here are some example schemas showing valid type-and-field combinations:
{ "type": "string", "enum": ["a", "b", "c"] }
{ "type": "string", "format": "date-time" }
{ "type": "integer", "format": "int64" }
{ "type": "number", "format": "double" }
{ "type": "boolean" }
{ "type": "array", "minItems": 3, "maxItems": 3, "items": { "type": ... } }
{ "type": "object",
"properties": {
"a": { "type": ... },
"b": { "type": ... },
"c": { "type": ... }
},
"nullable": true,
"required": ["c"],
"propertyOrdering": ["c", "b", "a"]
}
For complete documentation of the Schema fields as they're used in the Gemini API, see the Schema reference.
Property ordering
When you're working with JSON schemas in the Gemini API, the order of properties is important. By default, the API orders properties alphabetically and does not preserve the order in which the properties are defined (although the Google Gen AI SDKs may preserve this order). If you're providing examples to the model with a schema configured, and the property ordering of the examples is not consistent with the property ordering of the schema, the output could be rambling or unexpected.
To ensure a consistent, predictable ordering of properties, you can use the
optional propertyOrdering[]
field.
"propertyOrdering": ["recipeName", "ingredients"]
propertyOrdering[]
– not a standard field in the OpenAPI specification
– is an array of strings used to determine the order of properties in the
response. By specifying the order of properties and then providing examples with
properties in that same order, you can potentially improve the quality of
results. propertyOrdering
is only supported when you manually create
types.Schema
.
Schemas in Python
This section provides additional guidance on working with JSON schemas using the Python library.
When you're using the Python library, the value of response_schema
must be one
of the following:
- A type, as you would use in a type annotation (see the Python
typing
module) - An instance of
genai.types.Schema
- The
dict
equivalent ofgenai.types.Schema
The easiest way to define a schema is with a Pydantic type (as shown in the previous example):
Python
config={'response_mime_type': 'application/json',
'response_schema': list[Recipe]}
When you use a Pydantic type, the Python library builds out a JSON schema for you and sends it to the API. For additional examples, see the Python library docs.
The Python library supports schemas defined with the following types (where
AllowedType
is any allowed type):
int
float
bool
str
list[AllowedType]
AllowedType|AllowedType|...
- For structured types:
dict[str, AllowedType]
. This annotation declares all dict values to be the same type, but doesn't specify what keys should be included.- User-defined Pydantic models. This approach lets you specify the key names and define different types for the values associated with each of the keys, including nested structures.
Generating enum values
In some cases you might want the model to choose a single option from a list of
options. To implement this behavior, you can pass an enum in your schema. You
can use an enum option anywhere you could use a string
in the
responseSchema
, because an enum is an array of strings. Like a JSON schema, an
enum lets you constrain model output to meet the requirements of your
application.
For example, assume that you're developing an application to classify
musical instruments into one of five categories: "Percussion"
, "String"
,
"Woodwind"
, "Brass"
, or ""Keyboard"
". You could create an enum to help
with this task.
In the following example, you pass an enum as the
responseSchema
, constraining the model to choose the most appropriate option.
Python
from google import genai
import enum
class Instrument(enum.Enum):
PERCUSSION = "Percussion"
STRING = "String"
WOODWIND = "Woodwind"
BRASS = "Brass"
KEYBOARD = "Keyboard"
client = genai.Client(api_key="GEMINI_API_KEY")
response = client.models.generate_content(
model='gemini-2.0-flash',
contents='What type of instrument is an oboe?',
config={
'response_mime_type': 'text/x.enum',
'response_schema': Instrument,
},
)
print(response.text)
# Woodwind
The Python library will translate the type declarations for the API. However, the API accepts a subset of the OpenAPI 3.0 schema (Schema).
There are two other ways to specify an enumeration. You can use a
Literal
:
Python
Literal["Percussion", "String", "Woodwind", "Brass", "Keyboard"]
And you can also pass the schema as JSON:
Python
from google import genai
client = genai.Client(api_key="GEMINI_API_KEY")
response = client.models.generate_content(
model='gemini-2.0-flash',
contents='What type of instrument is an oboe?',
config={
'response_mime_type': 'text/x.enum',
'response_schema': {
"type": "STRING",
"enum": ["Percussion", "String", "Woodwind", "Brass", "Keyboard"],
},
},
)
print(response.text)
# Woodwind
Beyond basic multiple choice problems, you can use an enum anywhere in a JSON
schema. For example, you could ask the model for a list of recipe titles and
use a Grade
enum to give each title a popularity grade:
Python
from google import genai
import enum
from pydantic import BaseModel
class Grade(enum.Enum):
A_PLUS = "a+"
A = "a"
B = "b"
C = "c"
D = "d"
F = "f"
class Recipe(BaseModel):
recipe_name: str
rating: Grade
client = genai.Client(api_key="GEMINI_API_KEY")
response = client.models.generate_content(
model='gemini-2.0-flash',
contents='List 10 home-baked cookie recipes and give them grades based on tastiness.',
config={
'response_mime_type': 'application/json',
'response_schema': list[Recipe],
},
)
print(response.text)
The response might look like this:
[
{
"recipe_name": "Chocolate Chip Cookies",
"rating": "a+"
},
{
"recipe_name": "Peanut Butter Cookies",
"rating": "a"
},
{
"recipe_name": "Oatmeal Raisin Cookies",
"rating": "b"
},
...
]
Considerations
Keep the following considerations and best practices in mind when you're using a response schema:
- The size of your response schema counts towards the input token limit.
- By default, fields are optional, meaning the model can populate the fields or skip them. You can set fields as required to force the model to provide a value. If there's insufficient context in the associated input prompt, the model generates responses mainly based on the data it was trained on.
A complex schema can result in an
InvalidArgument: 400
error. Complexity might come from long property names, long array length limits, enums with many values, objects with lots of optional properties, or a combination of these factors.If you get this error with a valid schema, make one or more of the following changes to resolve the error:
- Shorten property names or enum names.
- Flatten nested arrays.
- Reduce the number of properties with constraints, such as numbers with minimum and maximum limits.
- Reduce the number of properties with complex constraints, such as
properties with complex formats like
date-time
. - Reduce the number of optional properties.
- Reduce the number of valid values for enums.
If you aren't seeing the results you expect, add more context to your input prompts or revise your response schema. For example, review the model's response without structured output to see how the model responds. You can then update your response schema so that it better fits the model's output.
What's next
Now that you've learned how to generate structured output, you might want to try using Gemini API tools: