X Xerobit

YAML Schema Validation — Validate YAML with JSON Schema and Ajv

YAML doesn't have built-in validation, but you can validate YAML structure using JSON Schema after parsing. Here's how to validate YAML files with JSON Schema, Ajv, pydantic,...

Mian Ali Khalid · · 5 min read
Use the tool
YAML ↔ JSON Converter
Convert between YAML and JSON formats with full fidelity.
Open YAML ↔ JSON Converter →

YAML itself has no type system or validation rules — any YAML is syntactically valid as long as it parses. To validate the structure and types of YAML, parse it to a plain object and run JSON Schema validation against it.

Use the YAML to JSON Converter to convert YAML to JSON for validation.

The approach: parse YAML, validate as JSON

import yaml from 'js-yaml';
import Ajv from 'ajv';

// 1. Parse YAML to a JS object
const config = yaml.load(yamlString);

// 2. Define a JSON Schema
const schema = { /* ... */ };

// 3. Validate
const ajv = new Ajv();
const validate = ajv.compile(schema);
const valid = validate(config);

if (!valid) {
  console.error(validate.errors);
}

Writing the schema

const configSchema = {
  type: 'object',
  required: ['database', 'server'],
  additionalProperties: false,
  properties: {
    database: {
      type: 'object',
      required: ['host', 'port', 'name'],
      properties: {
        host: { type: 'string' },
        port: { type: 'integer', minimum: 1, maximum: 65535 },
        name: { type: 'string', minLength: 1 },
        ssl: { type: 'boolean', default: false },
      },
    },
    server: {
      type: 'object',
      required: ['port'],
      properties: {
        port: { type: 'integer', minimum: 1024, maximum: 65535 },
        host: { type: 'string', default: '0.0.0.0' },
        debug: { type: 'boolean', default: false },
      },
    },
    logging: {
      type: 'object',
      properties: {
        level: {
          type: 'string',
          enum: ['debug', 'info', 'warn', 'error'],
          default: 'info',
        },
        format: {
          type: 'string',
          enum: ['json', 'text'],
        },
      },
    },
  },
};

Complete validation function

import yaml from 'js-yaml';
import Ajv from 'ajv';
import addFormats from 'ajv-formats';
import { readFileSync } from 'fs';

function validateYamlConfig(filePath, schema) {
  let parsed;
  
  // Parse YAML
  try {
    const content = readFileSync(filePath, 'utf8');
    parsed = yaml.load(content);
  } catch (err) {
    return { valid: false, errors: [`YAML parse error: ${err.message}`] };
  }
  
  // Validate against schema
  const ajv = new Ajv({ allErrors: true, useDefaults: true });
  addFormats(ajv);  // adds date, email, uri, etc. formats
  
  const validate = ajv.compile(schema);
  const valid = validate(parsed);
  
  if (!valid) {
    const errors = validate.errors.map(e =>
      `${e.instancePath || '(root)'}: ${e.message}`
    );
    return { valid: false, errors };
  }
  
  return { valid: true, data: parsed };
}

// Usage:
const result = validateYamlConfig('./config.yaml', configSchema);

if (!result.valid) {
  console.error('Config validation failed:');
  result.errors.forEach(e => console.error(' -', e));
  process.exit(1);
}

Python validation with pydantic

import yaml
from pydantic import BaseModel, Field, validator
from typing import Optional, Literal
from pathlib import Path

class DatabaseConfig(BaseModel):
    host: str
    port: int = Field(ge=1, le=65535)
    name: str
    ssl: bool = False

class ServerConfig(BaseModel):
    port: int = Field(ge=1024, le=65535)
    host: str = "0.0.0.0"
    debug: bool = False

class LoggingConfig(BaseModel):
    level: Literal["debug", "info", "warn", "error"] = "info"
    format: Literal["json", "text"] = "json"

class AppConfig(BaseModel):
    database: DatabaseConfig
    server: ServerConfig
    logging: LoggingConfig = LoggingConfig()

def load_config(path: str) -> AppConfig:
    with open(path) as f:
        data = yaml.safe_load(f)
    return AppConfig(**data)

# Usage:
try:
    config = load_config("config.yaml")
    print(f"Database: {config.database.host}:{config.database.port}")
except Exception as e:
    print(f"Config error: {e}")

Python validation with cerberus

import yaml
import cerberus

schema = {
    'database': {
        'type': 'dict',
        'required': True,
        'schema': {
            'host': {'type': 'string', 'required': True},
            'port': {'type': 'integer', 'min': 1, 'max': 65535},
            'name': {'type': 'string', 'required': True},
        }
    },
    'server': {
        'type': 'dict',
        'required': True,
        'schema': {
            'port': {'type': 'integer', 'required': True},
        }
    }
}

def validate_config(yaml_str):
    data = yaml.safe_load(yaml_str)
    v = cerberus.Validator(schema)
    if not v.validate(data):
        raise ValueError(f"Config errors: {v.errors}")
    return v.document

config = validate_config(open('config.yaml').read())

IDE YAML validation with schemas

Many IDEs support YAML schema associations that validate while you type.

VS Code: yaml-language-server

Install the YAML extension by Red Hat, then add schema associations to .vscode/settings.json:

{
  "yaml.schemas": {
    "./schemas/config.schema.json": "config.yaml",
    "https://json.schemastore.org/github-workflow.json": ".github/workflows/*.yml",
    "https://json.schemastore.org/docker-compose.json": "docker-compose*.yml"
  }
}

Inline schema declaration

Reference the schema directly in your YAML file:

# yaml-language-server: $schema=./config.schema.json

database:
  host: localhost
  port: 5432

The comment is recognized by the YAML language server.

SchemaStore

SchemaStore provides free JSON Schema definitions for hundreds of common config files:

  • docker-compose.yml
  • package.json
  • .github/workflows/*.yml
  • tsconfig.json
  • helm charts
  • k8s manifests

Most IDEs with YAML support automatically pick up these schemas for known file names.


Related posts

Related tool

YAML ↔ JSON Converter

Convert between YAML and JSON formats with full fidelity.

Written by Mian Ali Khalid. Part of the Data & Format pillar.