What is Standard Schema?
An introduction to Standard Schema and why FieldTest uses it.
Overview
Standard Schema is a language-agnostic specification for defining data structures and validation rules. It provides a common format that works across different programming languages, frameworks, and tools.
Think of it as a "universal language" for describing what your data should look like.
Why Standard Schema Matters
The Problem
Different validation libraries use different formats:
// Zod
const zodSchema = z.object({
title: z.string(),
count: z.number()
});
// Yup
const yupSchema = yup.object({
title: yup.string().required(),
count: yup.number().required()
});
// JSON Schema
const jsonSchema = {
type: "object",
properties: {
title: { type: "string" },
count: { type: "number" }
}
};
Each library has its own API and learning curve. Switching between them requires rewriting schemas.
The Solution
Standard Schema provides one format that works everywhere:
const standardSchema = {
version: '1',
name: 'example',
fields: {
title: { type: 'string', required: true },
count: { type: 'number', required: true }
}
};
This schema can be:
- ✅ Validated by FieldTest
- ✅ Understood by humans
- ✅ Generated by AI tools
- ✅ Shared across projects
- ✅ Converted to other formats
Core Concepts
1. Versioned
Schemas include a version number for future compatibility:
{
version: '1', // Currently version 1
name: 'user-profile',
fields: { /* ... */ }
}
When Standard Schema evolves, new versions will be introduced while maintaining backwards compatibility.
2. Named
Every schema has a unique name for identification:
{
version: '1',
name: 'blog-post', // Unique identifier
fields: { /* ... */ }
}
Names help with:
- Schema registration and reuse
- Error reporting
- Documentation generation
- Tool integration
3. Field-Based
Schemas define fields with types and constraints:
{
version: '1',
name: 'product',
fields: {
sku: {
type: 'string',
required: true,
description: 'Unique product identifier'
},
price: {
type: 'number',
required: true
},
tags: {
type: 'string',
array: true
}
}
}
Each field specifies:
- Type — Data type (string, number, boolean, date, array, object)
- Required — Whether the field must be present
- Array — Whether the field contains multiple values
- Description — Human-readable explanation
- Default — Default value if not provided
4. Metadata-Rich
Schemas can include metadata for documentation and tooling:
{
version: '1',
name: 'blog-post',
fields: { /* ... */ },
metadata: {
description: 'Schema for blog post frontmatter',
author: 'Jane Doe',
lastUpdated: '2025-01-15',
tags: ['content', 'markdown']
}
}
Supported Field Types
Standard Schema supports these primitive types:
Type | Description | Example |
---|---|---|
string | Text content | "Hello World" |
number | Numeric values | 42 , 3.14 |
boolean | True/false | true , false |
date | ISO date strings | "2025-01-15" , "2025-01-15T10:30:00Z" |
array | Lists of values | Set array: true on field |
object | Nested structures | For complex nested data |
String Type
fields: {
title: {
type: 'string',
required: true,
description: 'Post title'
}
}
Number Type
fields: {
age: {
type: 'number',
required: true
},
price: {
type: 'number',
required: false,
default: 0
}
}
Boolean Type
fields: {
published: {
type: 'boolean',
required: true,
default: false
}
}
Date Type
fields: {
publishedAt: {
type: 'date',
required: true
},
updatedAt: {
type: 'date',
required: false
}
}
Arrays
Use array: true
to indicate a field contains multiple values:
fields: {
tags: {
type: 'string',
array: true,
description: 'List of tags'
},
scores: {
type: 'number',
array: true
}
}
How FieldTest Uses Standard Schema
FieldTest implements Standard Schema for markdown validation:
import { loadUserSchema, validateWithSchema } from '@watthem/fieldtest';
import type { StandardSchemaV1 } from '@watthem/fieldtest';
// 1. Define schema
const schema: StandardSchemaV1 = {
version: '1',
name: 'blog-post',
fields: {
title: { type: 'string', required: true },
published: { type: 'boolean', required: true }
}
};
// 2. Load schema
const loadedSchema = loadUserSchema(schema);
// 3. Validate content
const markdown = `
---
title: "My Post"
published: true
---
Content here
`;
const result = validateWithSchema(markdown, loadedSchema);
if (result.valid) {
console.log('✓ Valid!');
}
Benefits for FieldTest Users
- Easy to learn — Simple, intuitive schema format
- Portable — Schemas work across different tools
- Type-safe — Full TypeScript support
- AI-friendly — LLMs understand Standard Schema
- Future-proof — Versioned for evolution
- Interoperable — Works with other Standard Schema tools
Comparison with Other Formats
vs. Zod
Zod (TypeScript-specific):
import { z } from 'zod';
const schema = z.object({
title: z.string(),
count: z.number().min(0).max(100)
});
Standard Schema (universal):
const schema = {
version: '1',
name: 'example',
fields: {
title: { type: 'string', required: true },
count: { type: 'number', required: true }
}
};
When to use:
- Zod — Complex runtime validation, TypeScript-only projects
- Standard Schema — Cross-platform, simple validation, AI integration
vs. JSON Schema
JSON Schema:
{
"type": "object",
"properties": {
"title": { "type": "string" },
"count": { "type": "number" }
},
"required": ["title", "count"]
}
Standard Schema:
{
version: '1',
name: 'example',
fields: {
title: { type: 'string', required: true },
count: { type: 'number', required: true }
}
}
When to use:
- JSON Schema — Complex validation, extensive ecosystem
- Standard Schema — Simpler syntax, better for content validation
Design Philosophy
Standard Schema follows these principles:
1. Simplicity First
Schemas should be easy to read and write. No complex nesting or obscure syntax.
// Good - clear and simple
{
version: '1',
name: 'user',
fields: {
name: { type: 'string', required: true }
}
}
// Avoid - unnecessarily complex
{
version: '1',
name: 'user',
fields: {
name: {
type: 'string',
validators: [{ type: 'required', value: true }],
transforms: [],
metadata: { level: 1 }
}
}
}
2. Language Agnostic
Schemas are plain JSON/JavaScript objects that work in any language.
3. Human and Machine Readable
Schemas should be understandable by developers, content creators, and AI tools.
4. Versioned for Evolution
The version
field allows the specification to evolve without breaking existing schemas.
Real-World Example
Here's a complete Standard Schema for a documentation page:
import type { StandardSchemaV1 } from '@watthem/fieldtest';
export const docPageSchema: StandardSchemaV1 = {
version: '1',
name: 'documentation-page',
fields: {
// Required fields
title: {
type: 'string',
required: true,
description: 'Page title shown in navigation'
},
description: {
type: 'string',
required: true,
description: 'Short description for SEO'
},
// Optional fields
author: {
type: 'string',
required: false,
description: 'Page author'
},
lastUpdated: {
type: 'date',
required: false,
description: 'Last modification date'
},
// Arrays
tags: {
type: 'string',
array: true,
description: 'Content tags for search'
},
relatedPages: {
type: 'string',
array: true,
description: 'Links to related documentation'
},
// Booleans with defaults
draft: {
type: 'boolean',
required: false,
default: false,
description: 'Whether page is a draft'
},
showToc: {
type: 'boolean',
required: false,
default: true,
description: 'Show table of contents'
}
},
metadata: {
description: 'Schema for documentation pages',
version: '1.0.0',
author: 'Docs Team'
}
};