Automatically convert schemas like Zod to prompts for AI SDK generate, OpenAI function calling, and structured LLM outputs
npm install prompt-schemaConvert Zod schemas to AI prompts in Markdown.


---
- What is this?
- Quick Start
- Themes
- Options
- Advanced Usage
- API Reference
- Supported Features
- License
---
When using LLMs with structured output (OpenAI function calling, AI SDK generateObject, etc.), you need to tell the model what schema to follow. This library converts your Zod schemas into clear, Markdown-formatted prompt instructions that LLMs understand well.
Before (raw JSON Schema dumped into prompt):
``json`
{
"type": "object",
"properties": {
"name": { "type": "string", "maxLength": 100 },
"email": { "type": "string", "format": "email" },
"age": { "type": "number", "minimum": 0, "maximum": 120 }
},
"required": ["name", "email", "age"]
}
After (prompt-schema output):
`Schema
- name: string (required • max 100 chars)
- email: string (required • format: email)
- age: number (required • min: 0 • max: 120)
`
---
`bash`
npm install prompt-schema zod
> Requires zod@^3.25.0 (includes both v3 and v4 APIs)
`typescript
import { getPrompts } from 'prompt-schema';
import { z } from 'zod/v3';
const schema = z.object({
name: z.string().max(100),
email: z.string().email(),
age: z.number().min(0).max(120),
});
const prompt = getPrompts(schema);
`
Output:
`Schema
- name: string (required • max 100 chars)
- email: string (required • format: email)
- age: number (required • min: 0 • max: 120)
`
---
Choose an output format that fits your use case. The standard, expanded, and condensed themes output Markdown, which LLMs parse reliably:
Clean and readable, optimized for AI prompts:
`Schema
- name: string (required)
- age: number (required • min: 0)
- email: string (required • format: email)
`
Ultra-compact for token efficiency:
``
name:str!
age:num![≥0]
email:str![@]
Includes full constraint details:
`Schema
- name: string (required)
- age: number (required • min: 0)
- email: string (required • pattern: ^[...] • format: email)
{ "name": "John Doe", "age": 30, "email": "john@example.com" }
`
Structured data for programmatic use:
`json`
{
"schema": {
"fields": [
{ "name": "name", "type": "string", "required": true },
{ "name": "age", "type": "number", "required": true, "constraints": { "min": 0 } },
{ "name": "email", "type": "string", "required": true, "constraints": { "format": "email" } }
]
}
}
`typescript`
const prompt = getPrompts(schema, { theme: 'condensed' });
---
| Option | Type | Default | Description |
| ---------- | --------------------------------------------------------- | ------------ | ---------------------------------------------------- |
| theme | 'standard' \| 'condensed' \| 'expanded' \| 'json' | 'standard' | Output format |maxDepth
| | number | 3 | Maximum nesting depth for objects/arrays |safe
| | boolean | false | Return fallback message on error instead of throwing |
---
Zod v4 supports .meta() for adding examples:
`typescript
import { getPrompts } from 'prompt-schema';
import { z } from 'zod/v4';
const schema = z
.object({
username: z.string().min(3).max(20),
age: z.number().min(18),
})
.meta({
examples: [{ username: 'john_doe', age: 25 }],
});
const prompt = getPrompts(schema, { theme: 'expanded' });
`
`typescript
import { z } from 'zod/v3';
// Unions
const unionSchema = z.object({
value: z.union([z.string(), z.number(), z.boolean()]),
});
// → value: string | number | boolean (required)
// Tuples
const tupleSchema = z.object({
coordinates: z.tuple([z.number(), z.number()]),
});
// → coordinates: [number, number] (required)
// Records
const recordSchema = z.object({
metadata: z.record(z.string(), z.string()),
});
// → metadata: Record
// Discriminated Unions
const notificationSchema = z.object({
notification: z.discriminatedUnion('type', [
z.object({ type: z.literal('email'), to: z.string().email() }),
z.object({ type: z.literal('sms'), phone: z.string() }),
]),
});
`
For advanced use cases, use the PromptSchema class directly:
`typescript
import { PromptSchema, zodV3Adapter, zodV4Adapter, jsonSchemaAdapter } from 'prompt-schema';
const converter = new PromptSchema();
converter.registerAdapter(zodV4Adapter);
converter.registerAdapter(zodV3Adapter);
converter.registerAdapter(jsonSchemaAdapter);
const prompt = converter.toPrompt(schema, { theme: 'expanded' });
`
See CONTRIBUTING.md for creating custom adapters.
---
Main entry point. Auto-detects Zod v3 or v4.
`typescript`
function getPrompts(schema: unknown, options?: ContextOptions): string;
`typescript`
class PromptSchema {
registerAdapter(adapter: SchemaAdapter): void;
toPrompt(schema: unknown, options?: ContextOptions): string;
getAdapters(): string[];
}
`typescript
interface ContextOptions {
theme?: 'standard' | 'condensed' | 'expanded' | 'json';
maxDepth?: number;
safe?: boolean;
}
interface SchemaAdapter
name: string;
canHandle: (schema: unknown) => boolean;
toJsonSchema: (schema: T, options?: unknown) => JsonSchema;
}
`
---
- Objects with nested properties
- Arrays with typed items
- Tuples (fixed-length arrays)
- Records (dynamic key-value maps)
- Enums and literal values
- Optional and nullable fields
- Discriminated unions
- Regular unions
- Date types (z.date() → format: date-time)
- All Zod constraints (min, max, length, regex, format)
- Zod v3 and v4
- Intersections - Treated as merged objects, may lose some type information
These Zod features don't translate to JSON Schema:
- transform(), refine() - Runtime-only validationslazy()
- - Recursive schemas would cause infinite loopsset()
- , map() - No JSON Schema equivalentbigint()
- , symbol(), function(), promise() - Not serializablenever()
- , unknown(), any(), void(), undefined(), nan()` - Fall back to generic types
---
MIT - Created by Joe Seifi