AI & JSON 15 min read

JSON Mode in LLMs: Getting Structured Output from ChatGPT, Claude & Gemini

Master JSON mode in ChatGPT, Claude, and Gemini. Learn how to get guaranteed structured output from AI models with practical code examples and best practices.

#ai #llm #json-mode #chatgpt #claude #gemini #structured-output

Getting reliable, structured data from AI models used to be a nightmare of prompt engineering and regex parsing. Now, with JSON mode, you can guarantee that ChatGPT, Claude, and Gemini return valid JSON every single time. This guide shows you exactly how to use it.

What is JSON Mode?

JSON mode is a feature that constrains an AI model to only output valid JSON. Without it, models can return markdown, explanatory text, or malformed JSON that breaks your parser.

Without JSON Mode:

bad-response.txt
text
Sure! Here's the data you requested:

```json
{
  "name": "John",
  "age": 30
}
```

Let me know if you need anything else!

Includes markdown, explanatory text—JSON.parse() fails!

With JSON Mode:

good-response.json
json
{
  "name": "John",
  "age": 30
}

Pure JSON—parses perfectly every time.

Key Insight: JSON mode guarantees syntactically valid JSON, but not semantically correct JSON. The AI might still return wrong field names or unexpected values. Always validate with a schema!

OpenAI JSON Mode (GPT-4, GPT-4o)

OpenAI offers two approaches: basic JSON mode and the newer Structured Outputs. Let's start with basic JSON mode.

Basic JSON Mode

openai-json-mode.js
javascript
import OpenAI from 'openai';

const openai = new OpenAI();

async function extractUserData(text) {
  const response = await openai.chat.completions.create({
    model: "gpt-4o",
    response_format: { type: "json_object" }, // Enable JSON mode
    messages: [
      {
        role: "system",
        content: `You are a data extraction assistant. 
Extract user information and return JSON with these fields:
- name (string)
- email (string or null)
- age (number or null)
- interests (array of strings)`
      },
      { role: "user", content: text }
    ]
  });

  return JSON.parse(response.choices[0].message.content);
}

// Usage
const result = await extractUserData(
  "Hi, I'm Sarah Chen, 28 years old. I love hiking and photography."
);
// { name: "Sarah Chen", email: null, age: 28, interests: ["hiking", "photography"] }
Required: When using JSON mode, you must mention "JSON" somewhere in your system or user message. OpenAI will return an error otherwise.

OpenAI Structured Outputs (Advanced)

In August 2024, OpenAI introduced Structured Outputs—a more powerful feature that guarantees the output matches a specific JSON Schema. This is the gold standard for reliability.

structured-outputs.ts
typescript
import OpenAI from 'openai';
import { z } from 'zod';
import { zodResponseFormat } from 'openai/helpers/zod';

const openai = new OpenAI();

// Define schema with Zod
const ProductSchema = z.object({
  name: z.string().describe("Product name"),
  price: z.number().describe("Price in USD"),
  category: z.enum(["electronics", "clothing", "home", "other"]),
  features: z.array(z.string()).describe("Key product features"),
  inStock: z.boolean()
});

async function extractProduct(description: string) {
  const response = await openai.beta.chat.completions.parse({
    model: "gpt-4o-2024-08-06",
    messages: [
      { role: "system", content: "Extract product information." },
      { role: "user", content: description }
    ],
    response_format: zodResponseFormat(ProductSchema, "product")
  });

  // TypeScript knows this is the correct type!
  return response.choices[0].message.parsed;
}

Claude JSON Output

Anthropic's Claude doesn't have an official "JSON mode" toggle, but it's extremely good at following instructions. For reliable JSON, use Claude's Tool Use feature.

claude-tool-use.js
javascript
import Anthropic from '@anthropic-ai/sdk';

const anthropic = new Anthropic();

const extractionTool = {
  name: "extract_person",
  description: "Extract person information from text",
  input_schema: {
    type: "object",
    properties: {
      name: { type: "string", description: "Person's full name" },
      email: { type: "string", description: "Email address" },
      company: { type: "string", description: "Company name" },
      title: { type: "string", description: "Job title" }
    },
    required: ["name"]
  }
};

async function extractPersonClaude(text) {
  const response = await anthropic.messages.create({
    model: "claude-3-5-sonnet-20241022",
    max_tokens: 1024,
    tools: [extractionTool],
    tool_choice: { type: "tool", name: "extract_person" }, // Force this tool
    messages: [{ role: "user", content: `Extract person info: ${text}` }]
  });

  const toolUse = response.content.find(block => block.type === 'tool_use');
  return toolUse.input; // Already parsed JSON!
}
Pro Tip: Claude's tool use with forced tool selection is the most reliable way to get structured JSON from Claude.

Gemini JSON Mode

Google's Gemini has native JSON mode support through the responseMimeType setting.

gemini-json.js
javascript
import { GoogleGenerativeAI } from "@google/generative-ai";

const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);

async function extractWithGemini(text) {
  const model = genAI.getGenerativeModel({ 
    model: "gemini-1.5-pro",
    generationConfig: {
      responseMimeType: "application/json" // Enable JSON mode
    }
  });

  const prompt = `Extract event details and return JSON with:
- eventName (string)
- date (YYYY-MM-DD format)
- location (string)
- attendees (array of strings)

Text: ${text}`;

  const result = await model.generateContent(prompt);
  return JSON.parse(result.response.text());
}

Provider Comparison

Feature OpenAI Claude Gemini
Basic JSON Mode ✅ response_format ⚠️ Prompt-based ✅ responseMimeType
Schema Enforcement ✅ Structured Outputs ✅ Tool Use ✅ responseSchema
Zod Integration ✅ Official helper ❌ Manual ❌ Manual
Reliability ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐

Common Issues & Solutions

Issue: AI Returns Markdown Code Blocks

Use JSON mode (OpenAI/Gemini) or Tool Use (Claude). If stuck with prompt-only, strip markdown:

strip-markdown.js
javascript
const cleanJson = response
  .replace(/```json\n?/g, '')
  .replace(/```\n?/g, '')
  .trim();

Issue: Wrong Field Types

Use Structured Outputs (OpenAI) or validate with Zod and retry on failure.

Issue: Truncated JSON

  • Increase max_tokens
  • Simplify your schema (fewer fields)
  • Request fewer items in arrays

Production Tips

  1. Log Raw Responses: Always log the raw AI response before parsing for debugging
  2. Implement Retries: Even with JSON mode, implement retry logic for transient failures
  3. Set Timeouts: AI calls can hang—always set reasonable timeouts
  4. Monitor Costs: JSON mode uses more tokens (schema description). Track usage.

Conclusion

JSON mode transforms AI from a "maybe it'll work" tool into a reliable data processing system:

  • OpenAI users: Use Structured Outputs with Zod for best results
  • Claude users: Use Tool Use with forced tool selection
  • Gemini users: Use responseMimeType with responseSchema
  • Everyone: Always validate with Zod, implement retries, log everything

Use our JSON tools with the TS/Zod tab to generate TypeScript interfaces and Zod schemas from sample JSON. Perfect for AI integrations!

About the Author

AT

Adam Tse

Founder & Lead Developer · 10+ years experience

Full-stack engineer with 10+ years of experience building developer tools and APIs. Previously worked on data infrastructure at scale, processing billions of JSON documents daily. Passionate about creating privacy-first tools that don't compromise on functionality.

JavaScript/TypeScript Web Performance Developer Tools Data Processing