C.W.K.
Stream
Lesson 02 of 04 · published

Structured Output / JSON

~14 min · json, schema, pydantic, structured-output

Level 0Spark
0 XP0/35 lessons0/10 achievements
0/140 XP to next level140 XP to go0% complete

Force the model to emit valid JSON

Set response_mime_type='application/json' and the model will produce JSON. Add a response_schema and the JSON will conform to that schema. The schema can be a Pydantic model, a TypedDict, or a raw dict.

Two cleanups it does for you

  1. No markdown fences (```json ... ```) wrapping the output.
  2. No trailing prose ("Here's the JSON: ...").

You get a clean parsable string in response.text, and (if you used Pydantic) a deserialized object in response.parsed.

This is not the same as function calling

  • Structured output = format the final response. The model talks back to you in JSON.
  • Function calling = the model wants to call your code mid-conversation. The function call is the response, not the final answer.

Use structured output for: extraction, classification, form-filling. Use function calling for: anything that requires action in your system.

Code

Pydantic schema — easiest path·python
from pydantic import BaseModel
from google import genai
from google.genai import types

client = genai.Client()

class Recipe(BaseModel):
    recipe_name: str
    ingredients: list[str]
    instructions: list[str]
    prep_minutes: int

response = client.models.generate_content(
    model='gemini-2.5-flash',
    contents='Give me a 30-minute chocolate chip cookie recipe.',
    config=types.GenerateContentConfig(
        response_mime_type='application/json',
        response_schema=Recipe,
    ),
)

# Parsed instance
recipe: Recipe = response.parsed
print(recipe.recipe_name, recipe.prep_minutes)
print(recipe.ingredients)
List-of-objects·python
class Recipe(BaseModel):
    recipe_name: str
    ingredients: list[str]

response = client.models.generate_content(
    model='gemini-2.5-flash',
    contents='Give me 3 cookie recipes.',
    config=types.GenerateContentConfig(
        response_mime_type='application/json',
        response_schema=list[Recipe],  # list of
    ),
)
recipes: list[Recipe] = response.parsed
TypeScript — same idea·typescript
import { GoogleGenAI, Type } from '@google/genai';

const ai = new GoogleGenAI({});

const response = await ai.models.generateContent({
  model: 'gemini-2.5-flash',
  contents: 'Give me 3 cookie recipes.',
  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 } },
          prepMinutes: { type: Type.INTEGER },
        },
        required: ['recipeName', 'ingredients'],
      },
    },
  },
});

const recipes = JSON.parse(response.text);

External links

Exercise

Write a Pydantic schema for a movie review with fields: title (str), year (int), rating (int 1-10), positives (list[str]), negatives (list[str]), one_line_summary (str). Send Flash three different movie titles and ask for a structured review. Confirm response.parsed gives you typed instances. Then introduce a malformed schema (something Gemini can't satisfy) and observe how it fails.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.