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:
- Parsing –
ParserHandler(packages/cli/src/linter/parser/handler.ts) parses the markdown, extracts YAML front-matter, and builds aParsedDesignSystemstructure. - Model resolution –
ModelHandler(packages/cli/src/linter/model/handler.ts) resolves token references, validates colors, dimensions, and typography, and produces a typedDesignSystemState. - Rule execution –
runLinter(packages/cli/src/linter/linter/runner.ts) applies built-in lint rules includingbrokenRef,contrast-ratio, andsection-order. - Tailwind emission –
TailwindEmitterHandler(packages/cli/src/linter/tailwind/handler.ts) converts resolved tokens into a Tailwind v3/v4 theme object.
The returned LintReport contains:
designSystem– The fully resolvedDesignSystemStatemodel 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.sectionsanddocumentSections– 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.mdprovides a TypeScript library for Node.js that parses DESIGN.md files and resolves tokens into a typedDesignSystemState.- The
lintfunction inpackages/cli/src/linter/lint.tsserves 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. diffandexportDesignfunctions 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →