GEMINI LABJP
API — Gemini 3.5 Flash is generally available and now powers gemini-flash-latest for sustained agentic and coding performanceAGENT — Managed Agents enter public preview, running stateful autonomous agents in Google-hosted isolated Linux sandboxesSEARCH — File Search adds multimodal search, embedding and searching images natively with gemini-embedding-2RESEARCH — A new Deep Research agent adds collaborative planning, visualization, MCP server integration, and File SearchSHEETS — Gemini in Sheets analyzes surrounding data to diagnose and fix formula errors in one clickROADMAP — Gemini 3.5 Pro slips to July for refinement; the Flash line leads for nowAPI — Gemini 3.5 Flash is generally available and now powers gemini-flash-latest for sustained agentic and coding performanceAGENT — Managed Agents enter public preview, running stateful autonomous agents in Google-hosted isolated Linux sandboxesSEARCH — File Search adds multimodal search, embedding and searching images natively with gemini-embedding-2RESEARCH — A new Deep Research agent adds collaborative planning, visualization, MCP server integration, and File SearchSHEETS — Gemini in Sheets analyzes surrounding data to diagnose and fix formula errors in one clickROADMAP — Gemini 3.5 Pro slips to July for refinement; the Flash line leads for now
Articles/API / SDK
API / SDK/2026-06-27Advanced

Your Gemini Structured Output Keys Keep Reordering — Pin Them With propertyOrdering

You constrained the shape with responseSchema, yet the JSON key order shifts between calls and your snapshot tests go red for no reason. Here is why field order is not guaranteed by default, how propertyOrdering fixes it, how Pydantic sets it for you, and how to align few-shot examples — all with working code.

Gemini API148Structured Output8propertyOrderingSnapshot TestingJSON Schema2

Premium Article

When you automate content operations across several sites, you end up asking Gemini for structured metadata constantly: give me the title, category, tags, and summary as JSON, then push that straight into the next stage. I felt safe because responseSchema constrained the shape. Then one day my snapshot tests started going red with no explanation.

Opening the diff was almost anticlimactic. The values were identical. The only thing that had changed was the order of the keys. An output that was {"title": ..., "tags": ...} came back the next run as {"tags": ..., "title": ...}. Right types, right values, and yet a text comparison reports a mismatch.

This article walks through that behavior — structured output does not guarantee field order by default — and how propertyOrdering pins it, including the trap that bites you once you add few-shot examples. It follows the same order in which I actually hit each issue as an indie developer maintaining pipelines across my own Dolice Labs sites.

Why the order moves — JSON schema being honest

The root of the confusion is in JSON itself: object keys carry no notion of order. The Schema object's properties (it descends from OpenAPI) is conceptually an unordered map, and the order the model writes fields in is decided at generation time. Even with temperature at 0 and a byte-identical prompt, sampling noise can swap the arrangement.

Google's structured output guidance says as much: if you depend on order, specify it explicitly. So there are two separate guarantees here — the type can be fixed, but the ordering has to be fixed separately. Miss that distinction and you lose time on the assumption that "I constrained the type, so the output must be fully determined," which is exactly the hole I fell into.

Here is the typical code that hands Gemini a raw dict schema.

# pip install google-genai
from google import genai
from google.genai import types
 
client = genai.Client(api_key="YOUR_GEMINI_API_KEY")
 
# A dict schema with no ordering specified
schema = {
    "type": "object",
    "properties": {
        "title": {"type": "string"},
        "category": {"type": "string"},
        "tags": {"type": "array", "items": {"type": "string"}},
        "summary": {"type": "string"},
    },
    "required": ["title", "category", "tags", "summary"],
}
 
resp = client.models.generate_content(
    model="gemini-2.5-flash",
    contents="Extract the metadata for this article: ...",
    config=types.GenerateContentConfig(
        response_mime_type="application/json",
        response_schema=schema,
    ),
)
print(resp.text)
# Sometimes {"title":..., "category":..., "tags":[...], "summary":...}
# Other times {"summary":..., "title":..., "tags":[...], "category":...}

Even though response_schema is set, the raw key order of resp.text wobbles between calls. If you only json.loads it and read values, nothing is wrong. The trouble appears only when you save and compare the generated JSON text itself. For me that was snapshot tests, plus a workflow that committed generated results to git as diffs.

Pin the order with propertyOrdering

The fix is simple: add propertyOrdering (camelCase in REST/JSON) to the Schema and list the property names in the order you want them emitted.

schema = {
    "type": "object",
    "properties": {
        "title": {"type": "string"},
        "category": {"type": "string"},
        "tags": {"type": "array", "items": {"type": "string"}},
        "summary": {"type": "string"},
    },
    # Add just this. The output stabilizes in this order.
    "propertyOrdering": ["title", "category", "tags", "summary"],
    "required": ["title", "category", "tags", "summary"],
}
 
resp = client.models.generate_content(
    model="gemini-2.5-flash",
    contents="Extract the metadata for this article: ...",
    config=types.GenerateContentConfig(
        response_mime_type="application/json",
        response_schema=schema,
    ),
)
# Output is always title -> category -> tags -> summary

propertyOrdering is an ordering hint, not a type constraint. Because validation still passes without it, it is easy to forget when you hand-write dict schemas — that has been my lived experience. If you have nested objects, each child Schema needs its own propertyOrdering too. Write it only at the top and the nested fields keep shuffling, and the diffs come back.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
Understand why responseSchema does not pin key order, and add one line of propertyOrdering to a dict schema to lock it down today
Learn how passing a Pydantic model as response_schema turns declaration order into propertyOrdering automatically, with verification code
Stop snapshot regressions that flapped purely on key order, using a two-layer fix: pin the order and normalize on compare
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Gemini Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

API / SDK2026-04-30
A Blueprint for Production-Grade Structured Output with Gemini API
A practical blueprint for running Gemini API's Structured Output reliably in production. Covers schema design, error handling, and performance optimization end-to-end.
API / SDK2026-06-20
Gemini API Grounding × Structured Output Guide — Turn Web Search Results into Typed JSON Data
Combine Gemini API Grounding with Google Search and Structured Output to extract real-time web information as type-safe JSON data. Practical implementation patterns included.
API / SDK2026-06-19
Generate Japanese and English in One Structured Call to Stop Term Drift
Generating Japanese and English versions separately makes terminology drift article by article. Pair both languages in one Gemini 3.5 Flash structured-output call, pin a glossary, and detect drift mechanically — with measured results.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →