# How the Diff Command Detects Token-Level Changes Between Design Systems

> Learn how the diff command detects token-level changes between DESIGN.md files by linting, extracting tokens, and performing key-by-key comparison to identify added, removed, or modified elements.

- Repository: [Google Labs Code/design.md](https://github.com/google-labs-code/design.md)
- Tags: how-to-guide
- Published: 2026-06-28

---

**The `diff` command detects token-level changes between design systems by linting two DESIGN.md files, extracting their design system token maps, and comparing them key-by-key using a `diffMaps` utility that classifies each token as added, removed, or modified based on JSON string equality.**

The `diff` command in the [`google-labs-code/design.md`](https://github.com/google-labs-code/design.md/blob/main/google-labs-code/design.md) repository provides precise detection of token-level changes between design system specifications. By parsing DESIGN.md files into structured token maps and applying a custom comparison algorithm, the tool identifies exactly which colors, typography scales, spacing values, and component definitions have changed between versions.

## Linting and Extracting Design System State

The comparison process begins in [`packages/cli/src/commands/diff.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/commands/diff.ts), where the command reads two DESIGN.md files and processes them through the linter. The `readInput` utility ingests file content, then the `lint` function parses each file into a `DesignSystemState` object containing token maps for colors, typography, rounding, spacing, and components.

```ts
const beforeReport = lint(beforeContent);
const afterReport  = lint(afterContent);

```

*Source:* [`packages/cli/src/commands/diff.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/commands/diff.ts) lines 46-48

These `DesignSystemState` objects provide the structured data required for comparison, with each token category stored as a `Map<string, V>` where keys represent token names and values contain the token definitions.

## Serializing Component Definitions

Component tokens require special handling before comparison. In the design.md specification, components are stored as `Map<string, ComponentDef>` objects. The `serializeComponents` function (defined in [`packages/cli/src/commands/diff.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/commands/diff.ts) lines 77-83) converts these complex structures into plain objects by extracting the `properties` entries, making structural differences comparable via standard equality checks.

```ts
function serializeComponents(components: Map<string, ComponentDef>) {
  const result = new Map<string, Record<string, unknown>>();
  for (const [name, comp] of components) {
    result.set(name, Object.fromEntries(comp.properties));
  }
  return result;
}

```

This serialization ensures that component property changes surface as standard object modifications during the diff process.

## The diffMaps Algorithm

The core comparison logic resides in [`packages/cli/src/utils.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/utils.ts) within the `diffMaps<V>` function. This utility receives two `Map<string, V>` objects and returns three arrays categorizing changes: `added`, `removed`, and `modified`.

The algorithm detects modifications by comparing `JSON.stringify` representations of values, ensuring deep equality checks for complex token definitions:

```ts
export function diffMaps<V>(before: Map<string, V>, after: Map<string, V>) {
  const added: string[] = [];
  const removed: string[] = [];
  const modified: string[] = [];

  for (const key of after.keys()) {
    if (!before.has(key)) added.push(key);
    else if (JSON.stringify(before.get(key)) !== JSON.stringify(after.get(key)))
      modified.push(key);
  }

  for (const key of before.keys()) {
    if (!after.has(key)) removed.push(key);
  }
  return { added, removed, modified };
}

```

*Source:* [`packages/cli/src/utils.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/utils.ts) lines 61-84

This approach guarantees that any structural change to a token value—whether a color hex code adjustment or a typography scale modification—triggers a modification classification.

## Aggregating Token Diffs

After processing, the command aggregates diffs across all five token categories. For each category (colors, typography, rounded, spacing, and components), the command invokes `diffMaps` with the respective maps from the `DesignSystemState` objects:

```ts
const diff = {
  tokens: {
    colors:    diffMaps(beforeReport.designSystem.colors,    afterReport.designSystem.colors),
    typography:diffMaps(beforeReport.designSystem.typography,afterReport.designSystem.typography),
    rounded:   diffMaps(beforeReport.designSystem.rounded,   afterReport.designSystem.rounded),
    spacing:   diffMaps(beforeReport.designSystem.spacing,   afterReport.designSystem.spacing),
    components:diffMaps(
      serializeComponents(beforeReport.designSystem.components),
      serializeComponents(afterReport.designSystem.components)
    ),
  },
  // ...
};

```

*Source:* [`packages/cli/src/commands/diff.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/commands/diff.ts) lines 50-59

The resulting structured diff object contains granular change arrays for each token type, enabling precise reporting of exactly which design tokens were added, removed, or modified.

## CLI Usage and Output Format

Invoke the diff command via the CLI to compare two DESIGN.md files:

```bash

# Compare two DESIGN.md files

design diff path/to/old/DESIGN.md path/to/new/DESIGN.md --format json

```

The command outputs a structured JSON object containing the classified changes and regression status:

```json
{
  "tokens": {
    "colors": {
      "added": ["brand-primary"],
      "removed": [],
      "modified": ["neutral-100"]
    },
    "typography": {
      "added": [],
      "removed": [],
      "modified": ["heading-1"]
    },
    "components": {
      "added": ["Button"],
      "removed": [],
      "modified": ["Card"]
    }
  },
  "findings": {
    "before": { "errors": 0, "warnings": 1 },
    "after":  { "errors": 0, "warnings": 2 },
    "delta":  { "errors": 0, "warnings": 1 }
  },
  "regression": true
}

```

The CLI exits with a non-zero status when regressions are detected—specifically when the "after" state introduces new errors or warnings compared to the "before" state.

## Programmatic Integration

You can leverage the diff functionality programmatically in Node.js applications by importing the linter and utility functions directly:

```ts
import { readFile } from 'fs/promises';
import { lint } from '@design/cli/linter';
import { diffMaps } from '@design/cli/utils';

async function diffDesignSystems(oldPath: string, newPath: string) {
  const oldContent = await readFile(oldPath, 'utf8');
  const newContent = await readFile(newPath, 'utf8');

  const oldReport = lint(oldContent);
  const newReport = lint(newContent);

  const colorDiff = diffMaps(oldReport.designSystem.colors, newReport.designSystem.colors);
  console.log('Color changes:', colorDiff);
}

```

This approach enables custom workflows for design system validation in CI/CD pipelines or automated testing suites.

## Summary

- The `diff` command uses the `diffMaps` utility in [`packages/cli/src/utils.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/utils.ts) to compare token maps key-by-key
- Changes are classified as **added**, **removed**, or **modified** using JSON stringification for equality checks
- Component definitions require serialization via `serializeComponents` before comparison to flatten complex property structures
- The CLI exits with non-zero status when regressions (new errors or warnings) are introduced between versions
- Token-level changes are reported across five categories: colors, typography, rounded, spacing, and components

## Frequently Asked Questions

### What file format does the diff command expect?

The diff command expects DESIGN.md files that conform to the design.md specification. These files are parsed into `DesignSystemState` objects containing typed token maps for colors, typography, spacing, and component definitions.

### How does diffMaps detect modified tokens?

The `diffMaps` function detects modifications by comparing `JSON.stringify` representations of values for keys present in both maps. If the stringified values differ, the key is classified as modified, ensuring deep comparison of complex token objects.

### Can I use the diff functionality programmatically without the CLI?

Yes. You can import `lint` from the linter module and `diffMaps` from the utils module to perform token comparisons programmatically. This enables integration into custom build tools, testing frameworks, or automation scripts.

### What constitutes a regression in the diff output?

A regression occurs when the "after" state contains more errors or warnings than the "before" state. The diff output includes a `regression` boolean flag and the CLI exits with a non-zero status code when regressions are detected, making it suitable for CI/CD quality gates.