Figma to Code: The Free Migration Workflow That Actually Works
A step-by-step guide to migrating Figma designs to production-ready React code using design tokens, Storybook, Tailwind, and the Figma MCP server. No paid tools required.
You have a polished Figma file. Every color token is named. Every spacing value earns its place. The typography scale actually makes sense.
Then you open the codebase.
#3B4FE0 hardcoded in eleven different places. Three Button implementations that look subtly different depending on which screen you're on. A styles.css so deep that nobody has scrolled to the bottom since 2023.
This is the gap between design and code — and it's quietly one of the most expensive problems in frontend work. The default solution teams reach for is a paid tool: Builder.io, Zeplin, Anima, some AI-powered SaaS that promises to collapse the distance. Those tools have their use cases. But if you're the developer who owns both the Figma file and the codebase, you can solve this yourself, locally, without a subscription, using tools that have matured significantly in the past year.
This is the workflow I actually use. Let me walk you through it.
Why most Figma migrations break down
The pattern is predictable. A designer ships a Figma file. The developer opens Dev Mode, reads some specs, and starts writing components by hand. It ships. Then the design changes in three places. Now you're hunting down everywhere that color was hardcoded. The Figma file and the code drift apart, slowly at first and then all at once.
The deeper issue isn't the tooling — it's the starting point. Most migrations treat Figma as a reference image: something to look at while you build. The moment you start implementing screens before establishing the underlying system, you've already lost.
The fix: build the design system first. Build screens on top of it.
Tokens before components. Components before pages. A living Storybook before a single feature ships. In that order, the whole problem changes character.
The migration sequence that works
| Step | What | Why |
|---|---|---|
| 1 | Export design tokens | Single source of truth for all visual values |
| 2 | Set up Storybook | Define component contracts before implementation |
| 3 | Connect Figma MCP | Let AI read your actual design, not screenshots |
| 4 | Build primitives | Tokens + MCP = consistent, documented components |
| 5 | Compose patterns | Combine primitives into reusable UI blocks |
| 6 | Assemble screens | Assembly, not design — AI knows your full inventory |
Most teams jump straight to step 6. That's why their migrations fail.
Step 1: Export your design tokens from Figma
Design tokens are the atoms of your system — named values for colors, spacing, border radii, shadows, typography. If your Figma file uses Variables (Figma's built-in token system, available in all paid plans), you can export them directly.
The tool: Tokens Studio (free tier)
Tokens Studio for Figma reads your Figma Variables and exports them as JSON in the W3C Design Token format. This format is an open standard — Style Dictionary, Tailwind, and most modern component systems understand it natively.
The output looks like this:
{
"color": {
"primary": { "$type": "color", "$value": "#3B82F6" },
"primary-hover": { "$type": "color", "$value": "#2563EB" },
"text-base": { "$type": "color", "$value": "#111827" }
},
"spacing": {
"4": { "$type": "dimension", "$value": "1rem" },
"6": { "$type": "dimension", "$value": "1.5rem" }
}
}
Nothing proprietary. Nothing that locks you into a platform.
Transform to Tailwind with Style Dictionary
Style Dictionary (open source, Amazon) takes that JSON and produces whatever output format you need. For Tailwind:
// style-dictionary.config.js
module.exports = {
source: ['tokens/**/*.json'],
platforms: {
css: {
transformGroup: 'css',
buildPath: 'src/styles/',
files: [{ destination: 'tokens.css', format: 'css/variables' }]
},
tailwind: {
transformGroup: 'js',
buildPath: 'src/',
files: [{ destination: 'tailwind.tokens.js', format: 'javascript/es6' }]
}
}
}
Run style-dictionary build and you get a tokens.css with CSS custom properties and a tailwind.tokens.js you extend your config with. From this point forward, your entire color palette and spacing scale are driven by a single file that traces directly back to Figma.
Automate the token pipeline
Add a GitHub Action that runs Style Dictionary whenever the tokens JSON changes. A designer updates a color in Figma, exports the JSON, and a PR opens automatically. You review, merge, and every component in the codebase updates without anyone touching a hex value.
Figma Variables
|
v
Tokens Studio (export JSON)
|
v
Git commit (tokens/*.json)
|
v
GitHub Action (Style Dictionary build)
|
v
CSS variables + Tailwind config
|
v
Every component updates automatically
Step 2: Set up Storybook before you write a single component
This is the piece most developers skip, and it costs them later.
The common approach is to build 20 components and then add Storybook as documentation afterwards. By then, component APIs are inconsistent, there's no standard for variants, and Storybook becomes something that looks nice in a demo but nobody actually maintains.
Starting with Storybook forces you to define your component contract before you implement it. Write the story first:
npx storybook@latest init
Then, before touching the Button implementation:
// Button.stories.tsx
import type { Meta, StoryObj } from '@storybook/react'
import { Button } from './Button'
const meta = {
title: 'Primitives/Button',
component: Button,
argTypes: {
variant: { control: 'select', options: ['primary', 'secondary', 'ghost'] },
size: { control: 'select', options: ['sm', 'md', 'lg'] },
disabled: { control: 'boolean' }
}
} satisfies Meta<typeof Button>
export default meta
type Story = StoryObj<typeof meta>
export const Primary: Story = {
args: { variant: 'primary', children: 'Get started' }
}
export const Ghost: Story = {
args: { variant: 'ghost', children: 'Learn more' }
}
Writing this first tells you exactly what props you need. The story becomes the spec. Then you implement the component to pass it — not the other way around.
Story-first vs code-first: what changes
| Approach | Component API | Documentation | Long-term maintenance |
|---|---|---|---|
| Code-first, stories later | Inconsistent — shaped by whatever the first screen needed | Incomplete — written after the fact, often outdated | High — APIs diverge across components |
| Story-first, then implement | Consistent — contract defined up front | Always current — stories are the spec | Low — single source of truth for behavior |
Step 3: Connect the Figma MCP server
This is where the workflow gets genuinely fast. Figma launched their official Dev Mode MCP server in mid-2025. It connects your Figma files directly to AI-powered coding environments — Cursor, Claude Code, VS Code Copilot — so your assistant can read the actual design instead of relying on screenshots or your description of it.
Setup is straightforward with the Figma desktop app installed:
// .cursor/mcp.json (or equivalent for your editor)
{
"mcpServers": {
"figma": {
"command": "npx",
"args": ["-y", "@figma/mcp-server"]
}
}
}
Restart the MCP client, select a component in Figma, and prompt your assistant to implement it. It calls get_design_context and gets back a structured React + Tailwind representation of your selection — including actual token names, spacing values, and typography specs.
Code Connect: the piece that makes it scale
The tool that makes this work properly at scale is Code Connect. It maps each Figma component to its code counterpart, so when the MCP server sees a "Button/Primary" in a layout, it uses your <Button variant="primary" /> instead of generating a new button from scratch. Without Code Connect, the AI is guessing. With it, it knows your entire component inventory.
Connecting a component takes about five minutes:
// Button.figma.tsx
import figma from '@figma/code-connect'
import { Button } from './Button'
figma.connect(Button, 'https://figma.com/design/YOUR_FILE_ID/...', {
props: {
variant: figma.enum('Variant', {
Primary: 'primary',
Secondary: 'secondary',
Ghost: 'ghost'
}),
children: figma.string('Label')
},
example: (props) => <Button {...props} />
})
Do this for each primitive as you build it. By the time you start implementing screens, the MCP server knows your full component library and will use it consistently.
MCP vs traditional design-to-code approaches
| Method | Input quality | Uses your components? | Understands tokens? | Speed |
|---|---|---|---|---|
| Manual from Figma Dev Mode | High (you read specs) | Only if you remember | Only if you check | Slow |
| Screenshot + AI prompt | Low (pixel guessing) | No | No | Fast but inaccurate |
| Figma MCP (no Code Connect) | High (structured data) | No — generates new ones | Yes | Fast |
| Figma MCP + Code Connect | High (structured data) | Yes — reuses your library | Yes | Fast and accurate |
Step 4: Build primitives in order
With tokens wired into Tailwind, Storybook running, and the MCP server connected, building primitives becomes a loop:
- Select a component in Figma
- Prompt: "Get design context for this component. Implement it using our token config — use token names, not raw Tailwind classes. Create a Storybook story covering all variants."
- Review the output
- Adjust if needed, commit
What previously took 2-3 hours per component is now a 20-minute review. The output is already aligned with your Figma design, uses your token names (not bg-blue-500), and includes a documented story.
Recommended primitive build order
Build in dependency order. Later components depend on earlier ones.
| Phase | Components | Dependencies |
|---|---|---|
| Foundation | Typography, Icon, Badge | Tokens only |
| Inputs | Button, Input, Checkbox, Select, Toggle | Foundation |
| Feedback | Alert, Toast, Tooltip, Progress | Foundation |
| Layout | Card, Modal, Dropdown, Tabs | Foundation + Inputs |
| Composition | FormField, DataTable, Navigation | All above |
Structure your directory so the hierarchy is explicit from the start:
src/
components/
primitives/ <- Button, Input, Badge, Icon
patterns/ <- Card, Modal, FormField, Dropdown
layouts/ <- PageShell, Sidebar, Header
tokens/
tokens.json <- Source of truth from Figma
tailwind.tokens.js
Primitives have no business logic. Patterns compose primitives. Layouts arrange patterns. When a new project starts, you pull from this library. The work compounds — not just in time saved, but in consistency that your future self will appreciate.
Step 5: Use your system as the foundation for every new project
This is the actual payoff.
Once your primitives are documented in Storybook and driven by tokens, starting a new project means customizing a proven foundation rather than building from zero.
For teams with multiple related products: monorepo
packages/
ui/ <- Your design system package
apps/
web/ <- imports @yourorg/ui
dashboard/ <- imports @yourorg/ui
mobile-web/ <- imports @yourorg/ui
A bug fix in Button propagates across all apps. A brand color update in Figma flows through tokens to every component. One source of truth, multiple consumers.
For freelancers or agency work: template repo
Keep a design-system starter that includes the full token pipeline, Storybook config, and a set of primitive components. When a new client project starts:
npx degit yourname/design-system new-client-project
Update the tokens JSON with the client's brand values, run Style Dictionary, and your entire Tailwind config is updated. Pixel-perfect foundation in under an hour. No SaaS, no subscriptions, everything local.
The complete toolchain at a glance
People assume this workflow requires paid tools. Here's the honest breakdown:
| Tool | Purpose | Cost | License |
|---|---|---|---|
| Tokens Studio | Export Figma Variables as JSON | Free tier | - |
| Style Dictionary | Transform tokens to CSS/Tailwind | Free | MIT |
| Storybook | Component documentation and testing | Free | MIT |
| Figma MCP Server | Design-to-code bridge for AI editors | Free | Requires Figma account |
| Code Connect | Map Figma components to code | Free | Requires Dev seat |
| Chromatic | Visual regression testing | Free (5k snapshots/month) | - |
The only real cost is a Figma account with Dev Mode access — which most teams are already paying for. Everything else is free, open source, and runs locally.
For teams in regulated industries — anything touching financial data, health records, or GDPR-sensitive information — the local-first nature of this stack matters. Your design tokens and component definitions don't pass through a third-party server. They stay on your machine.
The order is the architecture
Let me be direct about the one thing I see trip teams up most often: starting in the wrong place.
Teams pick tools before establishing workflow order. They find a great Storybook component library and try to adapt it to their Figma file. Or they hook up the Figma MCP server and start generating screens immediately, skipping tokens and primitives entirely.
The sequence that works:
- Tokens — export Figma Variables, transform to CSS/Tailwind
- Storybook — set up before components exist
- Primitives — Button, Input, Typography, Badge using MCP + token config
- Patterns — compose primitives into reusable UI blocks
- Screens — assemble patterns, not write new styles
If you follow this order, implementing a new screen becomes mostly an assembly task. Select the Figma frame, ask the MCP to implement it, and watch it pull your existing components together. The output is system-compliant by default because the AI knows your component inventory through Code Connect.
This is the workflow I follow when taking on fullstack development projects where the client needs not just a working app, but a codebase their team can actually maintain.
Final thought
The Figma-to-code problem stopped being a tooling problem about a year ago. The free stack — Tokens Studio, Style Dictionary, Storybook, and the Figma MCP server — is genuinely production-ready. What teams lack now isn't better tools. It's the discipline to build in the right order.
Tokens, then Storybook, then primitives, then screens. That's it.
If you're starting a project and want to get the foundation right from day one, a scoping sprint can prevent weeks of refactoring once you're deeper in. The best moment to build a design system is before the first component. The second best moment is right now.
Have questions about implementing this workflow, or working through a specific bottleneck in your design-to-code pipeline? Get in touch.

AI Agent & RAG Developer
AI Agent & RAG Developer with 10+ years of software engineering experience. Specialized in intelligent AI solutions for enterprises in the DACH & Nordic region.