This guide walks you through building a one-way design tokens pipeline that exports Figma Variables directly into a Tailwind CSS v4 config using Style Dictionary 4. You will have a working sync workflow in roughly two to three hours, and every future token update will take under five minutes to ship to production.

What You'll Build

  • A structured Figma Variables setup that maps cleanly to semantic design tokens
  • An automated export script using the Figma REST API and the Tokens Studio CLI
  • A Style Dictionary 4 transform pipeline that outputs a Tailwind v4 theme file
  • A single pnpm run tokens command that syncs everything from source to code
  • A tokens folder structure that works inside a monorepo or a standalone Next.js project

Prerequisites

  • Figma Professional or Organisation plan (required for Local Variables API access)
  • Node.js 20 or higher and pnpm 9
  • A Next.js 15 project using Tailwind CSS v4
  • A Figma Personal Access Token with file:read scope
  • Basic familiarity with JSON and the command line

Step 1: Structure Your Figma Variables the Right Way

Bad token structure is the most common reason this kind of pipeline breaks down later. Figma Variables support collections and groups, and you need to use both intentionally.

What collections should you create?

Create three collections inside your Figma file: Primitives, Semantic, and Component. Primitives hold raw values like hex codes and pixel numbers. Semantic tokens reference Primitives and carry meaning, for example color/surface/default or spacing/md. Component tokens are optional and reference Semantic tokens for specific UI patterns like button/background/primary.

This three-layer approach follows the Token Design Specification maintained by the W3C Design Tokens Community Group, which means your pipeline stays compatible with future tooling.

How should you name your variables?

Use forward slashes as separators inside Figma. color/brand/500 becomes color.brand.500 in JSON and --color-brand-500 in CSS. Avoid spaces and camelCase inside variable names. Consistency here saves hours of debugging later.

Set your Variable modes now if you need dark mode support. Name them light and dark inside the Semantic collection. Style Dictionary will handle the mode split during the transform step.

Step 2: Export Tokens from Figma Using the REST API

Figma's Variables REST API (available as of Figma v117, mid-2024) lets you pull all Variables from a file programmatically. You do not need a plugin for this step.

How do you fetch the variables?

Create a file called scripts/fetch-tokens.mjs at the root of your project.

// scripts/fetch-tokens.mjs
import { writeFileSync, mkdirSync } from 'fs';

const FILE_KEY = process.env.FIGMA_FILE_KEY;
const TOKEN = process.env.FIGMA_TOKEN;

async function fetchVariables() {
  const res = await fetch(
    `https://api.figma.com/v1/files/${FILE_KEY}/variables/local`,
    { headers: { 'X-Figma-Token': TOKEN } }
  );

  if (!res.ok) {
    throw new Error(`Figma API error: ${res.status} ${res.statusText}`);
  }

  const data = await res.json();
  mkdirSync('tokens/raw', { recursive: true });
  writeFileSync('tokens/raw/figma.json', JSON.stringify(data, null, 2));
  console.log('Figma variables saved to tokens/raw/figma.json');
}

fetchVariables();

Add your credentials to a .env.local file. Never commit this file to git.

FIGMA_FILE_KEY=your_file_key_here
FIGMA_TOKEN=your_personal_access_token_here

Run the script to verify the output.

node --env-file=.env.local scripts/fetch-tokens.mjs

You should see a tokens/raw/figma.json file containing your collections, variable modes, and resolved values.

What if the API returns a 403?

A 403 almost always means your Personal Access Token is missing the file:read scope, or the file is owned by a team on the Starter plan. Variables API access requires a paid Figma plan. Check both before retrying.

Step 3: Transform the Raw Output Into a W3C-Compatible Token File

The Figma Variables API returns its own schema, not the W3C Design Tokens format. You need to reshape the JSON before Style Dictionary can process it.

Why not use Tokens Studio instead?

Tokens Studio is a solid plugin and works well for teams that want a UI-based workflow. This guide uses the raw API approach because it runs in CI without browser access and gives you full control over the transform logic. Both approaches are valid.

Create scripts/transform-figma.mjs. This script reads the raw Figma output and writes a W3C-compatible token file per mode.

// scripts/transform-figma.mjs
import { readFileSync, writeFileSync, mkdirSync } from 'fs';

const raw = JSON.parse(readFileSync('tokens/raw/figma.json', 'utf8'));
const { variables, variableCollections } = raw.meta;

function resolveValue(variable, modeId, allVariables) {
  const value = variable.valuesByMode[modeId];
  if (value && value.type === 'VARIABLE_ALIAS') {
    const ref = allVariables[value.id];
    return `{${ref.name.replace(/\//g, '.')}}`;
  }
  return value;
}

const output = {};

for (const collection of Object.values(variableCollections)) {
  for (const modeId of Object.keys(collection.modes)) {
    const modeName = collection.modes[modeId];
    if (!output[modeName]) output[modeName] = {};

    for (const varId of collection.variableIds) {
      const variable = variables[varId];
      const keys = variable.name.split('/');
      let cursor = output[modeName];
      for (let i = 0; i < keys.length - 1; i++) {
        cursor[keys[i]] = cursor[keys[i]] || {};
        cursor = cursor[keys[i]];
      }
      cursor[keys[keys.length - 1]] = {
        $value: resolveValue(variable, modeId, variables),
        $type: variable.resolvedType.toLowerCase()
      };
    }
  }
}

mkdirSync('tokens/w3c', { recursive: true });
for (const [mode, tokens] of Object.entries(output)) {
  writeFileSync(`tokens/w3c/${mode}.json`, JSON.stringify(tokens, null, 2));
}
console.log('W3C token files written to tokens/w3c/');
node scripts/transform-figma.mjs

You should now have tokens/w3c/light.json and tokens/w3c/dark.json (or whatever mode names you used in Figma).

Step 4: Configure Style Dictionary 4 to Output a Tailwind v4 Theme

Style Dictionary 4 (released in late 2024) introduced a fully asynchronous, ESM-native API. It is a significant rewrite from v3. Make sure you install the correct version.

pnpm add -D style-dictionary@^4

Create style-dictionary.config.mjs at your project root.

// style-dictionary.config.mjs
import StyleDictionary from 'style-dictionary';

const modes = ['light', 'dark'];

for (const mode of modes) {
  const sd = new StyleDictionary({
    source: [`tokens/w3c/${mode}.json`],
    platforms: {
      css: {
        transformGroup: 'css',
        prefix: mode === 'dark' ? 'dark' : undefined,
        files: [
          {
            destination: `src/styles/tokens.${mode}.css`,
            format: 'css/variables',
            options: {
              selector: mode === 'dark' ? '.dark' : ':root'
            }
          }
        ]
      },
      tailwind: {
        transformGroup: 'js',
        files: [
          {
            destination: `src/styles/tokens.${mode}.js`,
            format: 'javascript/es6'
          }
        ]
      }
    }
  });

  await sd.buildAllPlatforms();
}

console.log('Style Dictionary build complete.');
node style-dictionary.config.mjs

This generates two CSS files with scoped custom properties and two JS modules you can import into your Tailwind config.

Step 5: Wire the Tokens Into Tailwind CSS v4

Tailwind CSS v4 uses a CSS-first config via @theme instead of tailwind.config.js. Your CSS token file maps directly to this format.

Open your main CSS file (typically src/app/globals.css) and import the generated token files.

@import 'tailwindcss';
@import './styles/tokens.light.css';
@import './styles/tokens.dark.css';

@theme {
  --color-brand-500: var(--color-brand-500);
  --color-surface-default: var(--color-surface-default);
  --spacing-md: var(--spacing-md);
  /* Map all semantic tokens you use in Tailwind classes here */
}

You can now use bg-surface-default or text-brand-500 as Tailwind utility classes. Dark mode switches automatically when the .dark class is applied to the HTML element, because your token file already scopes the overrides there.

Step 6: Automate the Pipeline With a Single Script

Add a tokens script to your package.json so the whole chain runs in order.

{
  "scripts": {
    "tokens": "node --env-file=.env.local scripts/fetch-tokens.mjs && node scripts/transform-figma.mjs && node style-dictionary.config.mjs"
  }
}
pnpm run tokens

A designer updates a colour in Figma, you run pnpm run tokens, commit the generated files, and open a pull request. The entire sync takes under a minute.

For teams that want this to run automatically, you can add a GitHub Actions workflow that triggers on a webhook from Figma's activity feed. At Lenka Studio, we typically set this up as a scheduled nightly job for client projects where daily token drift is a risk.

Should you commit generated token files?

Yes. Commit the files inside src/styles/ so your app builds without needing Figma API access at deploy time. Do not commit tokens/raw/ or tokens/w3c/ unless your team needs them for auditing. Add both folders to .gitignore if you prefer a clean repo and run the pipeline before every build instead.

Common Pitfalls to Avoid

  • Circular references in aliases. If a Semantic token aliases another Semantic token, Style Dictionary will throw a build error. Keep aliases pointing only one level up (Semantic to Primitive, Component to Semantic).
  • Variable names with spaces. Spaces in Figma variable names produce broken CSS custom property names. Rename them before running the pipeline.
  • Using the wrong Tailwind config format. Tailwind v4 does not use tailwind.config.js for theme values by default. If you are still on v3, the @theme block will not work and you need to export a JS config object instead.
  • Forgetting to regenerate on collection changes. Adding a new Figma collection after your initial setup requires re-running all three scripts. Document this for your team.

Frequently Asked Questions

Does this pipeline work with Tailwind CSS v3?

Yes, with one change. Instead of using @theme in your CSS, export the generated JS token file and reference it inside tailwind.config.js under the theme.extend key. The fetch and transform scripts stay identical.

Can I run this without a paid Figma plan?

No. The Variables REST API endpoint (/v1/files/:key/variables/local) is gated behind Figma Professional and Organisation plans as of 2026. On a Starter plan, you would need to use the Tokens Studio plugin and export manually instead.

How is this different from using Tokens Studio?

Tokens Studio is a Figma plugin that adds its own token schema on top of Figma Variables. This pipeline uses the native Figma Variables API, which means zero plugin dependency and better support for Figma's own multi-mode system. Tokens Studio is still useful for teams that need a visual token editor or work with design systems across multiple tools.

What if my Figma file has hundreds of variables?

The pipeline handles large files well because it processes everything in memory. Files with 500 to 1000 variables typically complete the full three-step pipeline in under 10 seconds on a standard laptop. If you see timeouts from the Figma API, add a retry with exponential backoff to fetch-tokens.mjs.

Can this run inside a CI/CD pipeline?

Yes. Store your FIGMA_FILE_KEY and FIGMA_TOKEN as repository secrets in GitHub Actions. Inject them as environment variables in your workflow file and run pnpm run tokens as a build step. If you want to avoid committing generated files, run the pipeline before the Tailwind build step so the CSS files exist before compilation.

Next Steps

Once your pipeline is running, the next step is to add a token linting step using the W3C Design Tokens validator to catch naming errors before they reach Style Dictionary. After that, look at adding Changesets to your repo so every token update produces a changelog entry automatically.

If you are also thinking about how your token system should reflect your brand at a strategic level, it is worth running a quick check with the Lenka Studio Brand Health Score to see whether your design system actually reflects your brand consistently across touchpoints.

If your team needs help building or auditing a design token pipeline for a production design system, the team at Lenka Studio works with SMBs across Australia, Singapore, Canada, and the US on exactly this kind of infrastructure. Get in touch and we can talk through your setup.