Validating Design Tokens Against JSON Schema in CI

Architectural Context & CI Integration

Design tokens serve as the single source of truth for UI consistency, but unvalidated token files frequently introduce runtime CSS failures, broken component states, and cascading style regressions. Integrating strict schema validation directly into your Token Scaling, Validation & CI Pipelines ensures that malformed payloads never reach production. By enforcing type constraints, required property checks, and value ranges at the commit stage, teams eliminate downstream debugging overhead and maintain architectural integrity across distributed repositories. This guardrail is critical for frontend architects and design ops engineers who must guarantee that every exported value adheres to standardized specifications before it is consumed by build tools like Stylelint, PostCSS, or CSS-in-JS compilers.

Precise Implementation Steps

To enforce token integrity, implement the following pipeline configuration:

  1. Define a Strict JSON Schema (Draft 2020-12): Map your token hierarchy using $ref pointers for shared types (e.g., color, spacing, typography). Enforce additionalProperties: false to reject undocumented keys.
  2. Install a Performant Validator: Add ajv-cli or ajv as a strict dev dependency. Avoid runtime-heavy parsers in CI environments.
  3. Create a Validation Script: Write a synchronous Node.js script that reads token directories, resolves aliases, and executes schema checks.
  4. Configure CI Runner Execution: Bind the script to pull_request and push events. Ensure the pipeline fails explicitly on exit 1.
  5. Cache Dependencies: Implement CI caching for node_modules and validator binaries to keep execution time under 15 seconds.

Schema Definition (schema/tokens.schema.json)

{
 "$schema": "https://json-schema.org/draft/2020-12/schema",
 "type": "object",
 "properties": {
 "color": {
 "type": "object",
 "patternProperties": {
 "^[a-z0-9-]+$": {
 "type": "object",
 "properties": {
 "value": { "type": "string", "pattern": "^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$" },
 "type": { "const": "color" }
 },
 "required": ["value", "type"],
 "additionalProperties": false
 }
 }
 }
 }
}

Validation Script (scripts/validate-tokens.js)

const Ajv = require("ajv");
const fs = require("fs");
const path = require("path");

const ajv = new Ajv({ allErrors: true, strict: true });
const schema = JSON.parse(fs.readFileSync(path.resolve(__dirname, "../schema/tokens.schema.json"), "utf8"));
const validate = ajv.compile(schema);

const tokenFiles = ["./tokens/core.json", "./tokens/themes.json"];
let hasErrors = false;

tokenFiles.forEach(file => {
 const data = JSON.parse(fs.readFileSync(file, "utf8"));
 const valid = validate(data);
 if (!valid) {
 console.error(`❌ Validation failed for ${file}:`);
 console.error(JSON.stringify(validate.errors, null, 2));
 hasErrors = true;
 }
});

process.exit(hasErrors ? 1 : 0);

CI Configuration (.github/workflows/validate-tokens.yml)

name: Token Schema Validation
on: [pull_request, push]
jobs:
 validate:
 runs-on: ubuntu-latest
 steps:
 - uses: actions/checkout@v4
 - uses: actions/setup-node@v4
 with: { node-version: '20', cache: 'npm' }
 - run: npm ci
 - run: node scripts/validate-tokens.js

CI Debugging & Diagnostic Workflows

When CI validation fails, isolate the root cause using structured diagnostics. Common failure modes include:

  • (A) Type Coercion Errors: Hex strings or CSS variables are parsed as integers or scientific notation by loose JSON parsers.
  • (B) Missing Required Properties: Nested token objects omit mandatory value or type keys during manual edits.
  • © Unresolved Alias References: Circular dependency loops or broken {token.path} syntax cause validation timeouts.

Run the validator with --verbose or --errors flags to extract exact line numbers and JSON paths. Cross-reference the error output with your token generation pipeline to determine if the issue originates from Figma export scripts, manual edits, or automated sync jobs. Implement a pre-commit hook using lint-staged to catch syntax errors before they trigger full CI runs.

CI Log Pattern Example

[ERROR] Token validation failed at path: $.spacing.base.value
[DETAIL] Expected type "string" but received "number" (16)
[ACTION] Check Figma export script for numeric coercion. Ensure all spacing values are wrapped in quotes.

Troubleshooting Matrix

Diagnostic Step Root Cause Resolution Pattern
Verify JSON syntax with jq or node -e 'JSON.parse(fs.readFileSync(...))' Schema draft mismatch (e.g., Draft 7 vs 2020-12) Pin validator dependencies in package.json to exact versions
Run validator in standalone mode to isolate CI environment variables Async token resolution not awaited before validation step Implement a pre-validation normalization script to strip metadata
Check for BOM characters or trailing commas in exported token files CI runner using outdated Node.js version incompatible with validator package Configure CI cache for node_modules and validator binary
Validate $ref resolution paths against CI working directory structure Token alias syntax deviating from schema patternProperties regex Add explicit type: ['string', 'number'] unions for flexible token values

Migration Strategy & Resolution Patterns

Migrating legacy token repositories to strict schema validation requires a phased approach. First, audit existing token files against a baseline schema using a dry-run mode that logs warnings without failing builds. Next, incrementally tighten constraints by enabling additionalProperties: false and enforcing explicit type definitions. Document resolution patterns for recurring CI blocks: standardize alias syntax, deprecate ambiguous value formats, and establish a token governance review process. For comprehensive schema definitions and advanced validation patterns, refer to our dedicated guide on JSON Schema Validation for Tokens. Finally, integrate automated audit scripts into your release pipeline to enforce semantic versioning bumps when schema violations are detected.

Migration Checklist