When teams scale from one app to dozens, design inconsistencies creep in—padding changes here, color swaps there, and suddenly "Figma to production" becomes a joke. At Xenotix Labs, we’ve delivered more than 30 Flutter applications for commerce, sports, and edtech without sacrificing design integrity. The secret isn’t more documentation or handoff meetings—it’s treating the Figma design system and Flutter codebase as a single, synchronized artifact.
Start with tokens, not components
Design tokens are the smallest reusable values in your system: colors, spacing, typography, shadows, and motion durations. Instead of scattering these across Figma files or Dart constants, define them once in a JSON file and generate both the Figma library and Flutter theme from it. For example:
{
"color": {
"primary": { "value": "#3F51FF" },
"surface": { "value": "#FFFFFF" }
},
"space": {
"xs": { "value": 4 },
"sm": { "value": 8 }
},
"radius": {
"card": { "value": 12 }
}
}A build script converts this JSON into a Dart file, tokens.dart, with strongly typed constants. Designers import the same JSON into Figma using the Tokens Studio plugin. When a token changes, it updates automatically in both Figma and the app. There’s no room for disagreement between design and code—both share the same source of truth.
Build components that reflect design tokens
Components like buttons, inputs, and cards sit on top of tokens. Each component exists in two places: as a Figma component with variants and properties, and as a Flutter widget with named parameters that match those properties. Crucially, every Flutter widget references tokens, not hard-coded values:
XButton(
label: 'Submit',
variant: ButtonVariant.primary,
onPressed: () => print('Pressed'),
)This ensures that when a designer adjusts the primary color token, every XButton with variant: ButtonVariant.primary updates instantly. No manual adjustments. No drift.
Pre-build layouts to reduce widget sprawl
Many teams waste time reinventing the same layouts: screens with app bars, modals with titles and actions, lists with search and pagination. Instead of rebuilding these from scratch for every project, we created reusable layout primitives in our internal package:
XScaffold(title, body, primaryAction)— a standard screen with a top app bar, main content, and a primary action button.XBottomSheet(title, body, dismissAction, confirmAction)— a modal sheet with a header, body, and two buttons.XListPage(searchBar, items, onLoadMore, emptyState)— a paginated list with search and empty state handling.
New projects start at the layout level, not the widget level. A login screen might use just two widgets: an XScaffold and an XInput—not twenty custom components.
Consolidate everything into a single package
Avoid splitting tokens, components, and layouts into separate packages early on. Premature separation creates dependency pain and forces engineers to juggle multiple imports. Instead, use one shared package, xenotix_design, structured like this:
tokens/— generated from JSON, imported into both Figma and Flutter.components/— reusable widgets likeXButton,XCard, andXInput.layouts/—XScaffold,XListPage, and other layout primitives.icons/— custom icons plus Lucide icons.test/— visual regression tests.
Apps pull this package as a Git or path dependency. Updates propagate automatically when apps update their pubspec.yaml. Versions follow semantic rules: major versions for breaking changes, minor for new components or fixes. Apps pin to a major version and update minor versions independently.
Eliminate handoff friction with a shared workflow
The Figma-to-Flutter handoff is often the biggest source of frustration. Our workflow removes it entirely:
- Designers work in Figma using the shared design system linked to tokens.
- They publish a Figma frame with notes on interactions, copy, and edge cases.
- Engineers open the frame, identify existing components, and flag new ones.
- If a new component is needed, designer and engineer co-design it in the shared library first.
- Both Figma and Flutter implementations update simultaneously.
- Engineers compose the screen using existing components.
There’s no handoff document. No last-minute padding adjustments. No “can you change this 14 to 16?” because spacing is a token—it updates everywhere at once.
Turn the design system into a living Storybook
We built a Flutter Storybook app that renders every component, variant, and state in a single navigable interface. Designers can browse it on their phones. Engineers can point to a button and say, “This exact component already exists—here’s how to use it.”
The Storybook also serves as a regression test surface. Every component has visual snapshot tests that run on every pull request. If a button grows taller by one pixel, the test fails before a designer notices.
Five lessons for teams building their first Flutter design system
- Tokens first, components second. A component built without tokens is technical debt in disguise.
- One package, not three. Don’t split your system prematurely—wait until you truly need separation.
- Storybook from week one. It’s the fastest way to catch inconsistencies before they spread.
- Visual diff tests in CI. Catches subtle changes that humans miss.
- Customize via tokens, not forks. Override colors or spacing with tokens instead of duplicating widgets per app.
If you’re scaling across multiple apps and need them to feel like one cohesive product, a unified design system is the answer. The days of “Figma to production” jokes are over—when design and code share a single source of truth, consistency scales effortlessly.
AI summary
Learn how to build a scalable Flutter design system from Figma using tokens, components, and Storybook to eliminate drift across 30+ apps.