Workspace

Token Pipeline (Figma → DTCG → dist)

How design tokens flow from Figma to compiled CSS/SCSS/Tailwind output.

Fetch

Terminal
handoff-app fetch

Pulls the raw Figma export, local styles (color, typography, effects) and component instance/variant data, and writes it to the project's tokens.json snapshot ({exportsOutputDirectory}/{figma_project_id}/tokens.json, exported/<project-id>/tokens.json by default). This snapshot is the input the rest of the pipeline builds on.

`fetch` alone doesn't produce what `push` sends

The tokens step of push/push:all reads public/api/tokens.json, a different file, written by handoff-app start / dev / build:app when they persist the client config. fetch never writes it. So a fresh fetch followed straight by push:tokens either pushes the previous snapshot or fails with "No tokens snapshot found" — run a build (or start) in between.

Build (tokens:build)

Terminal
handoff-app tokens:build

Runs in two steps:

  1. Auto-migration: if design-system/tokens/ is empty or missing but a Figma snapshot exists, Handoff migrates the legacy raw export into DTCG 2025.10 format under design-system/tokens/{primitive,semantic}/. This runs automatically on first use; pass --skip-migrate to opt out. If a brands.sharedCss + brands.entries config is set (for hand-authored brand CSS custom properties instead of Figma-exported color styles), those files are parsed and merged into the manifest at this step too.

  2. Style Dictionary transform: every *.tokens.json file under design-system/tokens/ (including any hand-authored files, e.g. a hand-written spacing.tokens.json) is run through Style Dictionary v4 and written to design-system/dist/:

    OutputFormat
    css/tokens.cssCSS custom properties
    scss/_tokens.scssSass variables
    tailwind/theme.cssTailwind 4 @theme {} block
    dtcg/tokens.resolved.jsonAlias-resolved DTCG passthrough

    If no brand is configured, Handoff synthesizes a default brand from the resolved color tokens so the Colors foundation page always has something to render.

Hand-authored tokens survive migration

Some token categories, spacing is the common example, are hand-authored rather than Figma-extracted. They're safe because the migration step is all-or-nothing, not a merge: needsMigration() returns false as soon as it finds any *.tokens.json anywhere under design-system/tokens/, so the migration is skipped entirely and nothing is overwritten. The Style Dictionary step then picks up every file it finds, hand-authored ones included.

Push

Terminal
handoff-app push:tokens   # or push:all, which includes this step

Sends the compiled DTCG manifest + dist output to POST /api/registry/dtcg, stored in the registry's singleton handoff_registry_dtcg row, plus the raw Figma snapshot to POST /api/registry/tokens. See API → /api/registry for both endpoints.

Consumption

Foundation pages (/foundations/colors, /typography, etc.) and the TokenOutputTabs component read compiled token output through getDataProvider(), StaticDataProvider reads design-system/dist/ off the filesystem in workspace dev mode; DynamicDataProvider reads the handoff_registry_dtcg row in registry mode. Same rendering code, same data shape, either mode, see Concepts → Tokens for the page-level detail and Architecture → The DATABASE_URL switch for the provider pattern itself.

On this page