Core concepts
Collections, modes and token files
Section titled “Collections, modes and token files”DTA follows Figma’s variable model. A collection groups variables; a mode is one set of values for all of them (a brand, a theme, a breakpoint). On disk, every collection and mode is one JSON file named {Collection}.{Mode}.json:
tokens/Primitives.Value.json one collection, one modetokens/Brand(Alias).BrandA.json one collection, a mode per brandtokens/Brand(Alias).BrandB.jsontokens/ScreenType.Desktop.json one collection, a mode per breakpointInside, the files use the W3C Design Tokens (DTCG) format: nested groups, and tokens with $type and $value. The full format: Token files.
Aliases and unique names
Section titled “Aliases and unique names”A value in braces points at another token: "$value": "{Colors.Foundation.Blue.500}". In Figma the same path reads Colors/Foundation/Blue/500; DTA converts between the two when it pulls and pushes.
Aliases carry no collection name, so variable names must be unique across all collections. That is what lets DTA resolve {Colors.Foundation.Blue.500} wherever it lives, and it is the one rule DTA asks your Figma file to follow.
dta graph shows the alias structure, and dta lint fails on aliases that point nowhere or in a circle.
Layers
Section titled “Layers”Most token sets end up with layers, whatever they call them. DTA works with any names, but its checks and defaults speak this model:
| Layer | Example collection | Modes | Values |
|---|---|---|---|
| Primitives | Primitives |
one | raw values: #0057b8, 8 |
| Brand | Brand(Alias) |
one per brand | aliases into the primitives |
| Dimension | ScreenType |
one per breakpoint | aliases or values that differ per screen |
dta analyze reads a Figma file and suggests which collection plays which role, and dta init uses that to propose collections and brands. The semantic-must-alias lint rule keeps a brand layer made of aliases only.
What the build makes of it
Section titled “What the build makes of it”dta build writes one set of files for the single-mode collections and one theme per brand:
- Single-mode collections (the primitives) become
:rootcustom properties invariables.css(aliases stayvar()references) andbase.css(values resolved). - Each brand listed in
brandsbecomesthemes/<brand>.css, scoped to[data-brand="<brand>"]. Switch brands by setting the attribute on any element,<html data-brand="branda">for the whole page. - The breakpoint collection named in
breakpointsis added tovariables.css: its default mode on:root, the other modes inside their media queries. - JavaScript and Tailwind files are written next to them.
[data-brand="branda"] { --colors-brand-primary: var(--colors-foundation-blue-500); --colors-brand-primary-dark: var(--colors-foundation-blue-700); --colors-brand-accent: var(--colors-foundation-sky-500); …}Every file and its format: Outputs.
Config
Section titled “Config”The project config is dta.config.ts (also .mts, .js, .mjs or .json). Unknown keys are rejected, so a typo shows up as an error instead of being ignored:
export default { figma: { source: 'file' }, // 'api' on an Enterprise plan tokens: { dir: 'tokens' }, collections: ['Primitives', 'Brand(Alias)', 'ScreenType'], // default: all brands: ['BrandA', 'BrandB'], breakpoints: { collection: 'ScreenType', default: 'Mobile', // on :root modes: { Tablet: '(min-width: 768px)', Desktop: '(min-width: 1024px)' }, }, outputs: { formats: ['css', 'tailwind-v4'], // default: all four ('tailwind-v3', 'js' too) css: { outDir: 'output/css' }, tailwind: { outDir: 'output/tailwind' }, }, lint: { rules: { 'semantic-must-alias': { severity: 'error', collections: ['Brand(Alias)'] } } },}Once DTA is installed as a package, defineConfig from design-token-authority wraps the object for editor completion; it changes nothing else.
Every key, with its type and default: Configuration. A dta.config.json can point "$schema" at /schemas/dta.config.schema.json on this site for completion in editors.