Using design.md as a Library in Node.js for Programmatic API Integration

The @google/design.md npm package exposes a TypeScript library that lets you parse DESIGN.md files, resolve design tokens into a typed model, run lint rules, and export Tailwind CSS configurations directly from Node.js code.

The google-labs-code/design.md repository ships as the npm package @google/design.md, offering both a command-line interface and a fully typed Node.js library for design system automation. When using design.md as a library in Node.js, you gain direct access to the same parsing, validation, and export engines that power the CLI, allowing seamless integration into build pipelines, CI workflows, and custom design tooling.

Package Architecture and Entry Points

The library is structured as a modular TypeScript codebase with distinct entry points for different use cases. While the CLI bootstrap resides in packages/cli/src/index.ts and uses citty to register sub-commands (lint, diff, export, spec), the programmatic API exposes these capabilities as importable functions.

All core components are implemented as pure TypeScript classes, making them safe to invoke in any Node.js environment without side effects. The public API surface is intentionally minimal, with the lint function serving as the primary entry point for most integrations.

Core API: The lint Function

The lint function is the main public API exported from @google/design.md/linter. Located in packages/cli/src/linter/lint.ts, this function accepts a raw DESIGN.md string and returns a comprehensive LintReport object.

The function executes a four-stage pipeline internally:

  1. ParsingParserHandler (packages/cli/src/linter/parser/handler.ts) parses the markdown, extracts YAML front-matter, and builds a ParsedDesignSystem structure.
  2. Model resolutionModelHandler (packages/cli/src/linter/model/handler.ts) resolves token references, validates colors, dimensions, and typography, and produces a typed DesignSystemState.
  3. Rule executionrunLinter (packages/cli/src/linter/linter/runner.ts) applies built-in lint rules including brokenRef, contrast-ratio, and section-order.
  4. Tailwind emissionTailwindEmitterHandler (packages/cli/src/linter/tailwind/handler.ts) converts resolved tokens into a Tailwind v3/v4 theme object.

The returned LintReport contains:

  • designSystem – The fully resolved DesignSystemState model with all tokens and references computed.
  • findings – An array of rule violations with severity levels and messages.
  • summary – Aggregated counts of errors, warnings, and infos.
  • tailwindConfig – A generated Tailwind CSS theme configuration object.
  • sections and documentSections – Parsed markdown sections for documentation generation.

Additional Programmatic APIs

Beyond linting, the library exposes specialized modules for differencing and export operations.

Diff API

Import diff from @google/design.md/diff to compare two versions of a DESIGN.md file programmatically. This function analyzes token-level changes and detects regressions where new errors or warnings appear.

Export API

Import exportDesign from @google/design.md/export to convert DESIGN.md content into external formats such as DTCG (Design Tokens Community Group) JSON. This enables interoperability with design tools like Figma, Adobe XD, or Style Dictionary.

Utility Functions

The formatOutput helper in packages/cli/src/utils.ts provides standardized serialization for report objects, supporting JSON and other output formats with proper formatting options.

Practical Implementation Examples

Basic Programmatic Linting

import { lint } from '@google/design.md/linter';
import { formatOutput } from '@google/design.md/utils';
import { readFile } from 'fs/promises';

// Load DESIGN.md content
const designMarkdown = await readFile('path/to/DESIGN.md', 'utf8');

// Execute lint
const report = lint(designMarkdown);

// Access resolved design system
console.log(report.designSystem);

// Process findings
report.findings.forEach(finding => {
  console.log(`[${finding.severity}] ${finding.message}`);
});

// Export Tailwind config as JSON
console.log(formatOutput(report.tailwindConfig, { format: 'json' }));

Detecting Design System Changes

import { diff } from '@google/design.md/diff';
import { readFile } from 'fs/promises';

const before = await readFile('v1/DESIGN.md', 'utf8');
const after = await readFile('v2/DESIGN.md', 'utf8');

const diffReport = diff(before, after);

console.log('Token changes:', diffReport.tokens);
console.log('Regression detected:', diffReport.regression); // true if new errors/warnings added

Exporting to DTCG Format

import { exportDesign } from '@google/design.md/export';
import { writeFile } from 'fs/promises';

const design = await readFile('DESIGN.md', 'utf8');
const dtcg = exportDesign(design, { format: 'dtcg' });

await writeFile('tokens.json', JSON.stringify(dtcg, null, 2));

Running from npm Scripts

When invoking the CLI from package.json scripts, use the designmd command (Windows-compatible alias avoiding .md file-association conflicts):

{
  "scripts": {
    "design:lint": "designmd lint src/DESIGN.md",
    "design:export": "designmd export src/DESIGN.md --format dtcg"
  }
}

Summary

  • @google/design.md provides a TypeScript library for Node.js that parses DESIGN.md files and resolves tokens into a typed DesignSystemState.
  • The lint function in packages/cli/src/linter/lint.ts serves as the primary API, returning design system models, lint findings, and Tailwind configurations.
  • Internal handlers (ParserHandler, ModelHandler, TailwindEmitterHandler) are accessible through the lint pipeline and execute in pure TypeScript without side effects.
  • diff and exportDesign functions enable version comparison and DTCG JSON export for design token interoperability.
  • All components can be imported directly into build pipelines, enabling automated validation and transformation of design systems in CI/CD workflows.

Frequently Asked Questions

How do I install design.md for programmatic use in Node.js?

Install the package via npm or yarn using npm install @google/design.md. The package includes TypeScript definitions and exposes sub-path exports such as @google/design.md/linter, @google/design.md/diff, and @google/design.md/export, allowing you to import only the specific functionality you need without loading the entire CLI bundle.

What does the lint function return?

The lint function returns a LintReport object containing the resolved designSystem (typed as DesignSystemState), an array of findings with rule violations, a summary of error counts, a generated tailwindConfig object, and parsed markdown sections. This comprehensive report enables you to programmatically validate design tokens and generate CSS configuration in a single operation.

Can I use design.md without invoking the CLI?

Yes. While the package includes a CLI bootstrap in packages/cli/src/index.ts built with citty, all core functionality is available as importable library functions. The lint, diff, and exportDesign functions operate as pure TypeScript code with no CLI dependencies, making them suitable for server-side applications, custom build tools, and automated testing environments.

Which file handles the conversion of design tokens to Tailwind CSS?

The TailwindEmitterHandler in packages/cli/src/linter/tailwind/handler.ts is responsible for converting the resolved DesignSystemState into a Tailwind CSS theme configuration. This handler supports both Tailwind v3 and v4 formats and is automatically invoked during the lint function execution, with results available in the tailwindConfig property of the returned report.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →