Structured Outputs
JSON ModeGet guaranteed JSON responses that match your schema. Perfect for data extraction, API responses, and type-safe applications.
Overview
Structured outputs ensure the model returns valid JSON matching your specification. Two modes are available:
JSON Mode
Guarantees valid JSON output. The structure is flexible—you describe the format in your prompt.
JSON Schema
Guarantees the output matches your exact JSON Schema definition with strict: true.
Supported Models
| Model | JSON Mode | JSON Schema | Strict Mode |
|---|---|---|---|
| gpt-4o | ✓ | ✓ | ✓ |
| gpt-4o-mini | ✓ | ✓ | ✓ |
| claude-3.5-sonnet | ✓ | Via prompt | — |
| gemini-2.0-flash | ✓ | ✓ | — |
JSON Mode
The simplest way to get JSON responses. Set response_format: { type: "json_object" } and include "JSON" in your prompt:
const response = await client.chat.completions.create({
model: 'gpt-4o',
response_format: { type: 'json_object' },
messages: [
{
role: 'system',
content: 'You are a helpful assistant. Always respond with valid JSON.'
},
{
role: 'user',
content: 'List 3 programming languages with their year of creation.'
}
]
});
const data = JSON.parse(response.choices[0].message.content);
console.log(data);
// {
// "languages": [
// { "name": "Python", "year": 1991 },
// { "name": "JavaScript", "year": 1995 },
// { "name": "Go", "year": 2009 }
// ]
// }Important: When using JSON mode, you MUST include the word "JSON" in your system or user message.
JSON Schema Mode
Define an exact schema and get guaranteed conformance with strict mode:
const response = await client.chat.completions.create({
model: 'gpt-4o',
response_format: {
type: 'json_schema',
json_schema: {
name: 'user_profile',
strict: true,
schema: {
type: 'object',
properties: {
name: { type: 'string' },
age: { type: 'integer' },
email: { type: 'string', format: 'email' },
interests: {
type: 'array',
items: { type: 'string' }
}
},
required: ['name', 'age', 'email'],
additionalProperties: false
}
}
},
messages: [
{
role: 'user',
content: 'Create a profile for a 28-year-old software engineer named Alex who likes hiking.'
}
]
});
const profile = JSON.parse(response.choices[0].message.content);
// Guaranteed to match the schema:
// {
// "name": "Alex",
// "age": 28,
// "email": "alex@example.com",
// "interests": ["hiking", "software engineering"]
// }Using with Zod
Combine Zod schemas with structured outputs for end-to-end type safety:
import { z } from 'zod';
import { zodToJsonSchema } from 'zod-to-json-schema';
// Define your schema with Zod
const ProductSchema = z.object({
name: z.string().describe('Product name'),
price: z.number().positive().describe('Price in USD'),
category: z.enum(['electronics', 'clothing', 'food', 'other']),
inStock: z.boolean(),
tags: z.array(z.string()).optional()
});
// Convert to JSON Schema
const jsonSchema = zodToJsonSchema(ProductSchema, 'Product');
const response = await client.chat.completions.create({
model: 'gpt-4o',
response_format: {
type: 'json_schema',
json_schema: {
name: 'product',
strict: true,
schema: jsonSchema.definitions?.Product || jsonSchema
}
},
messages: [
{
role: 'user',
content: 'Create a product listing for wireless earbuds priced at $79.'
}
]
});
// Parse and validate with Zod
const product = ProductSchema.parse(JSON.parse(response.choices[0].message.content));
console.log(product);
// TypeScript knows the exact type!Install with: npm install zod zod-to-json-schema
Data Extraction Example
Extract structured data from unstructured text like invoices, receipts, or documents:
const response = await client.chat.completions.create({
model: 'gpt-4o',
response_format: {
type: 'json_schema',
json_schema: {
name: 'invoice_data',
strict: true,
schema: {
type: 'object',
properties: {
vendor_name: { type: 'string' },
invoice_number: { type: 'string' },
date: { type: 'string', format: 'date' },
line_items: {
type: 'array',
items: {
type: 'object',
properties: {
description: { type: 'string' },
quantity: { type: 'integer' },
unit_price: { type: 'number' },
total: { type: 'number' }
},
required: ['description', 'quantity', 'unit_price', 'total']
}
},
subtotal: { type: 'number' },
tax: { type: 'number' },
total: { type: 'number' }
},
required: ['vendor_name', 'invoice_number', 'date', 'line_items', 'total']
}
}
},
messages: [
{
role: 'user',
content: `Extract structured data from this invoice:
ACME Corp Invoice #INV-2024-001
Date: January 15, 2024
Widget Pro x5 @ $29.99 = $149.95
Gadget Basic x2 @ $19.99 = $39.98
Subtotal: $189.93
Tax (10%): $18.99
Total: $208.92`
}
]
});Enum Constraints
Use enums to constrain values to a specific set:
const response = await client.chat.completions.create({
model: 'gpt-4o',
response_format: {
type: 'json_schema',
json_schema: {
name: 'sentiment_analysis',
strict: true,
schema: {
type: 'object',
properties: {
sentiment: {
type: 'string',
enum: ['positive', 'negative', 'neutral', 'mixed']
},
confidence: {
type: 'number',
minimum: 0,
maximum: 1
},
keywords: {
type: 'array',
items: { type: 'string' },
maxItems: 5
}
},
required: ['sentiment', 'confidence', 'keywords']
}
}
},
messages: [
{
role: 'user',
content: 'Analyze: "The product quality is great but shipping was slow."'
}
]
});
// Output is guaranteed to have valid enum values:
// { "sentiment": "mixed", "confidence": 0.85, "keywords": ["quality", "great", "shipping", "slow"] }Schema Limitations
Supported Types
string, number, integer, boolean, array, object, null
Strict Mode Requirements
- • All properties must be in
requiredarray - • Must set
additionalProperties: false - • Max 100 properties per object
- • Max 5 levels of nesting
Not Supported in Strict Mode
- •
oneOf,anyOf,allOf - •
$refreferences - •
patternfor strings - •
minItems,maxItemsfor arrays
Best Practices
Keep Schemas Simple
Simpler schemas produce more reliable outputs. Split complex extractions into multiple calls if needed.
Add Descriptions
Use the description field in your schema to guide the model on expected values.
Handle Optional Fields
In strict mode, use type: ["string", "null"] for optional fields instead of omitting them.
Validate on Your End
Even with strict mode, validate the response with Zod or similar for defense in depth.

