Skip to content

The Pipeline

Dispersa processes design tokens through a pipeline from resolution to rendered output. Tokens flow from a resolver document through shared stages (run once) and per-output stages (run for each output), being resolved, filtered, transformed, and formatted along the way.

Click any stage below to see what it does:

CSSJSON...
Resolve

Loads the DTCG resolver document and validates it against the official DTCG 2025.10 JSON schema, catching structural errors like missing versions, invalid set references, or malformed modifiers. After validation, sets are merged in order and modifier contexts (themes, platforms, densities) are applied to produce the raw token tree for each permutation.

Input:Resolver document + modifier inputs
Output:Raw token tree per permutation
StageScopeDescription
1. ResolveSharedLoad and validate the resolver document, merge sets, apply modifier contexts
2. PreprocessSharedRun optional preprocessors on the raw token tree
3. ParseSharedValidate and flatten token documents, resolve references and aliases
4. LintSharedRun lint rules on resolved tokens (optional, configured via lint option)
5. Global FilterSharedRemove tokens globally before per-output processing
6. Global TransformSharedTransform all tokens before per-output processing
7. FilterPer-outputFurther narrow tokens for each specific output
8. TransformPer-outputConvert token values and names for the target platform
9. RenderPer-outputFormat tokens into CSS, JSON, JS, Tailwind, Swift, Kotlin, etc.

Stages 1-6 run once for the entire build and produce a resolved, flat token set. Stages 7-9 run per output, so each output can have its own filters, transforms, and renderer.

  1. Resolve — Loads and parses the resolver document. The resolver is validated against the official DTCG 2025.10 JSON schema, catching structural errors like missing versions, invalid set references, or malformed modifiers. After validation, sets are merged in order and modifier contexts (themes, platforms, densities) are applied to produce the raw token tree for each permutation.

  2. Preprocess — Runs optional preprocessors on the raw token tree. Use this to strip vendor metadata, inject computed tokens, or normalize legacy formats before parsing.

  3. Parse — Resolves JSON Pointer $ref references (including external files), flattens nested groups to dot-path keys (e.g. color.action.brand), inherits group-level $type, and resolves {token.name} alias references with circular dependency detection. During parsing, each token document is validated against the DTCG format schema, and individual tokens are checked against their type-specific schemas (color, dimension, etc.). Token names and group structures are also validated per the DTCG specification.

  4. Lint — Runs lint rules on resolved tokens to check for issues like naming conventions, missing descriptions, deprecated usage, or custom rules from plugins. Linting is optional and configured via the lint option in BuildConfig. Results are included in build output when linting is enabled.

  5. Global Filter — Global filters from BuildConfig reduce the token set for all outputs. Tokens excluded here never reach any output.

  6. Global Transform — Global transforms from BuildConfig run on all tokens (e.g. nameKebabCase()). These apply before any per-output transforms.

  1. Filter — Per-output filters from each OutputConfig further narrow the globally transformed set for that specific output.

  2. Transform — Per-output transforms run after global transforms (e.g. colorToHex() for CSS). They convert token values and names for the target format.

  3. Render — The renderer formats the final tokens into the target output: CSS custom properties, JSON, JS/TS modules, Tailwind @theme blocks, Swift/SwiftUI, Kotlin/Compose, or any custom format via defineRenderer.

import { build, css, json } from 'dispersa'
import { byType, nameKebabCase } from 'dispersa/transforms'
await build({
// Global: applied to ALL outputs (stages 5-6)
filters: [byType('color')],
transforms: [nameKebabCase()],
outputs: [
css({
name: 'css',
// Per-output: applied AFTER global (stages 7-8)
transforms: [
/* color transforms */
],
}),
json({
name: 'json',
// Per-output: different transforms for this output
transforms: [
/* other transforms */
],
}),
],
})