Skip to content
  • Gemini
  • Zod
  • LLM
  • TypeScript
  • AI Engineering

How to Get Reliable JSON from the Gemini API with Zod

By Published 1 min read (or skim, I won't know)

To get reliable JSON from Google Gemini, request JSON output with a response schema, then parse and validate every response with Zod on your server before your app uses it. Retry on failure instead of trusting raw model output.

The problem

In HireMate, my AI resume checker, the model returns a skill-gap analysis, a preparation plan, and interview questions. The UI expects a precise shape. If one field is missing or a list comes back as a string, the page breaks.

Step 1: Define the shape once with Zod

import { z } from "zod";

export const Analysis = z.object({
  matchScore: z.number().min(0).max(100),
  missingSkills: z.array(z.string()).min(1),
  prepPlan: z.array(z.object({ step: z.string(), resources: z.array(z.string()) })),
  interviewQuestions: z.array(
    z.object({ type: z.enum(["technical", "behavioral"]), question: z.string(), answer: z.string() }),
  ),
});
export type Analysis = z.infer<typeof Analysis>;

Step 2: Ask Gemini for JSON

import { GoogleGenAI } from "@google/genai";

const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });

const res = await ai.models.generateContent({
  model: "gemini-2.5-flash",
  contents: buildPrompt(resume, jobDescription),
  config: { responseMimeType: "application/json" },
});

Step 3: Validate, then retry

async function analyse(input: Input, attempts = 2): Promise<Analysis> {
  const raw = await callGemini(input);
  const parsed = Analysis.safeParse(JSON.parse(raw));
  if (parsed.success) return parsed.data;
  if (attempts > 0) return analyse(input, attempts - 1);
  throw new Error("The AI response could not be validated.");
}

Key takeaways

  • Define the schema once and reuse it for validation and TypeScript types.
  • Never trust raw model output. Validate on the server.
  • Retry on failure and show a friendly message if retries run out.

Frequently asked questions

How do I get JSON output from the Gemini API?

Ask for JSON in the prompt, set the response MIME type to application/json, provide a response schema, and then validate the parsed result in your own code with a schema library such as Zod before using it.

Why validate LLM output with Zod if the model already uses a schema?

Model-side schemas reduce errors but do not guarantee business rules such as minimum lengths, allowed values, or non-empty arrays. Zod validation on your server catches anything malformed and gives you typed data in TypeScript.

What should happen when LLM output fails validation?

Retry the request once or twice, optionally including the validation error in the prompt, and fall back to a friendly error message if it still fails. Never render unvalidated model output directly.