Build a Token Pipeline with Style Dictionary
Transform design tokens from JSON to CSS, iOS, Android in one command. One source of truth, every platform covered.
What you will need
Version 20 or later. This runs Style Dictionary and the npm scripts you will set up.
Terminal on Mac, the built-in terminal in VS Code, or Windows Terminal. You will run a few install and build commands.
Either an existing token file exported from Figma or Tokens Studio, or a willingness to create one. The scaffold in step 1 generates an example for you.
Time to install, scaffold, configure, and run your first multi-platform build.
- 01
JSON tokens
Design decisions in a single source of truth
- 02
Transforms
Style Dictionary applies naming, format, and value rules
- 03
CSS
Custom properties for web
- 04
iOS + Android
Swift enums and XML resources
Why This Matters for Your Design System
I maintained four separate token files for two years. One for CSS. One for iOS. One for Android. One “source of truth” in Figma that was never actually true because someone always forgot to update one of the other three.
Style Dictionary killed that entire problem in a single afternoon. You define your tokens once, in one JSON file, and it generates every platform format on command. This workflow shows you how to set it up so you never manually translate a hex value to a UIColor again.
Step 1: Install Style Dictionary
Open your terminal and create a new project folder. Then install Style Dictionary as a development dependency.
mkdir my-design-tokens
cd my-design-tokens
npm init -y
npm install -D style-dictionary
Alternatively, you can use Style Dictionary’s built-in scaffolding to generate a starter project with example tokens:
npx style-dictionary init basic
This creates a complete working example with token files, a configuration, and build outputs for multiple platforms.
Why this step matters: Starting with the scaffolded project gives you a working reference. You can see exactly what inputs produce which outputs before you start customizing anything.
Step 2: Organize Your Token Files
Style Dictionary reads tokens from JSON files. The structure is flexible, but a clear hierarchy keeps things manageable as your system grows.
Create a tokens/ folder with this structure:
tokens/
color/
base.json
semantic.json
spacing/
base.json
typography/
base.json
Here is an example tokens/color/base.json:
{
"color": {
"base": {
"blue": {
"100": { "$value": "#DBEAFE" },
"500": { "$value": "#3B82F6" },
"900": { "$value": "#1E3A8A" }
},
"gray": {
"100": { "$value": "#F3F4F6" },
"500": { "$value": "#6B7280" },
"900": { "$value": "#111827" }
}
}
}
}
And an example tokens/color/semantic.json that references base values:
{
"color": {
"background": {
"primary": { "$value": "{color.base.gray.100}" },
"inverse": { "$value": "{color.base.gray.900}" }
},
"action": {
"primary": { "$value": "{color.base.blue.500}" }
}
}
}
Why this step matters: Splitting tokens across files makes them easier to find and maintain. Style Dictionary deep-merges all files automatically, so you can organize by category without worrying about how they connect. The reference syntax ({color.base.blue.500}) means changing a base value automatically propagates to every semantic token that uses it.
Step 3: Create the Configuration File
The configuration tells Style Dictionary where to find your tokens and what to output. Create a config.json in your project root:
{
"source": ["tokens/**/*.json"],
"platforms": {
"css": {
"transformGroup": "css",
"buildPath": "build/css/",
"files": [
{
"destination": "variables.css",
"format": "css/variables"
}
]
},
"ios": {
"transformGroup": "ios-swift",
"buildPath": "build/ios/",
"files": [
{
"destination": "DesignTokens.swift",
"format": "ios-swift/class.swift",
"className": "DesignTokens"
}
]
},
"android": {
"transformGroup": "android",
"buildPath": "build/android/",
"files": [
{
"destination": "colors.xml",
"format": "android/resources",
"resourceType": "color",
"filter": {
"type": "color"
}
}
]
}
}
}
Why this step matters: Each platform block defines a transform group (which converts values to the right format), a build path (where files go), and output files. The transformGroup is doing the heavy lifting. For CSS, it converts colors to hex strings. For iOS, it converts them to UIColor calls. For Android, it wraps them in XML resource tags. You write tokens once. Style Dictionary handles the translation.
Step 4: Run the Build
Add a build script to your package.json:
{
"scripts": {
"build:tokens": "style-dictionary build"
}
}
Then run it:
npm run build:tokens
You should see output like this:
css
✔ build/css/variables.css
ios
✔ build/ios/DesignTokens.swift
android
✔ build/android/colors.xml
Open the generated files to verify the output. Your CSS file should look something like:
:root {
--color-base-blue-100: #DBEAFE;
--color-base-blue-500: #3B82F6;
--color-base-blue-900: #1E3A8A;
--color-background-primary: #F3F4F6;
--color-background-inverse: #111827;
--color-action-primary: #3B82F6;
}
Why this step matters: This is the moment where everything clicks. One command, three platform outputs, all consistent. If you change blue.500 from #3B82F6 to #2563EB, every platform file updates on the next build. No searching, no find-and-replace.
Step 5: Add Dark Mode Support
Most design systems need multiple themes. Style Dictionary handles this through separate source files and platform configurations.
Create tokens/color/dark.json:
{
"color": {
"background": {
"primary": { "$value": "{color.base.gray.900}" },
"inverse": { "$value": "{color.base.gray.100}" }
},
"action": {
"primary": { "$value": "{color.base.blue.500}" }
}
}
}
Then add a dark theme platform to your config:
{
"css-dark": {
"transformGroup": "css",
"buildPath": "build/css/",
"files": [
{
"destination": "variables-dark.css",
"format": "css/variables",
"options": {
"selector": "[data-theme='dark']"
}
}
],
"source": ["tokens/color/base.json", "tokens/color/dark.json"]
}
}
Why this step matters: Theme support is where token pipelines prove their worth. Without a pipeline, maintaining light and dark themes means manually updating two sets of values in every platform. With Style Dictionary, you define the overrides once and the build handles the rest.
Step 6: Integrate with Your Workflow
Now that your pipeline works locally, connect it to the rest of your workflow.
The full loop looks like this: designer updates a token in Figma, Tokens Studio pushes the JSON to GitHub, GitHub Actions runs Style Dictionary, and the built files are published as a package. End to end, no manual steps.
Why this step matters: A build tool running on your laptop is useful. A build tool running automatically in a pipeline is transformational. The goal is to remove yourself from the publishing process entirely so you can focus on design decisions instead of file management.
What You Get
- One source of truth. All platform outputs derive from the same JSON tokens.
- Platform-native formats. CSS custom properties, Swift constants, Android XML resources, Kotlin Compose objects, and more.
- Automatic reference resolution. Semantic tokens that reference primitives are resolved at build time.
- Extensibility. Style Dictionary supports custom transforms, formats, and filters when the built-in options are not enough.
Common Pitfalls
- Circular references. If Token A references Token B and Token B references Token A, the build will fail. Keep your reference chain one-directional: primitives to semantic, never the reverse.
- Missing
$valuekey. Style Dictionary v4 uses the DTCG format with$value. Older tutorials may showvaluewithout the dollar sign. Check which version you are using. - Forgetting to rebuild. Changes to token JSON files are not reflected until you run the build command again. Automate this with a file watcher or CI pipeline.
Build a working pipeline from one hex value to three platforms
-
Scaffold a minimal pipeline with one primitive and one semantic token
Create a folder. Run
npm init -y && npm install -D style-dictionary. Addtokens/color/base.jsonwith one color (color.base.blue.500=#3B82F6). Addtokens/color/semantic.jsonwith one reference (color.action.primary={color.base.blue.500}). Copy theconfig.jsonfrom Step 3 of this guide with all three platforms (css, ios, android). Runnpx style-dictionary build. Verify three files appear underbuild/.build/css/variables.csscontains both--color-base-blue-500and--color-action-primarybuild/ios/DesignTokens.swiftcompiles if you paste it into a Swift Playgroundbuild/android/colors.xmlcontains the resolved hex value, not a token reference- All three files were generated from a single
npx style-dictionary buildcommand
-
Change one primitive, watch three platforms update
Change
color.base.blue.500from#3B82F6to#2563EBintokens/color/base.json. Run the build again. Open all three output files. Confirm the new hex appears in every one, including the semantic token that referenced it. This is the moment where the pipeline proves itself. Without Style Dictionary, that change is one find-and-replace per platform. With it, it is one save.- The new hex
#2563EBappears in all three output files color.action.primarystill references the updated value (you did not have to edit the semantic token)- You can now describe to a teammate in two sentences why this pattern beats maintaining separate token files per platform
- You have a tiny repo you can copy and adapt for a real project tomorrow
- The new hex
Finished this lesson?
Mark it complete to track your progress through "Design System Automation".
The guides alone saved me a full day of work every sprint.
- All guides, prompts, and templates
- Starter kits and templates
- New content every week
- Priority support