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 as a strict dev dependency. The ajv-cli package provides the ajv CLI command for use in scripts.
  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/dist/2020"); // Use Ajv v8+ for Draft 2020-12 support
const fs = require("fs");
const path = require("path");

const ajv = new Ajv({ allErrors: 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);

Note on Ajv versions: Ajv v8+ is required for JSON Schema Draft 2020-12 support. Import from ajv/dist/2020 (not ajv directly) when using Draft 2020-12 features. If your schema uses Draft-07 syntax, the standard new Ajv() import from ajv v8 works without the /dist/2020 specifier.

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. Always wrap values in quotes in JSON.
  • (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 allErrors: true in the Ajv config to extract all errors in a single pass. 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 node -e "JSON.parse(require('fs').readFileSync('tokens/core.json','utf8'))" Schema draft mismatch (e.g., Draft 7 vs 2020-12) Pin ajv to exact version in package.json; use ajv/dist/2020 for Draft 2020-12
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 ajv version Configure CI cache for node_modules and pin Node.js version in actions/setup-node
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: