figma_tokens_gen
Generate Flutter Color constants and palette maps from Figma design-token
JSON exports.
Point it at the JSON your design team exports, and get a checked-in Dart file
with one static const Color per token — no runtime parsing, no asset lookup,
no string keys in your widget code.
Container(color: AppColors.primaryMain);
Requirements
| Version | |
|---|---|
| Dart SDK | 3.13.0 or newer |
| Flutter (for the generated code) | 3.47.0 or newer |
Flutter 3.47 moved the Material widgets into their own
material_ui package, so that is what
the generated file imports:
dependencies:
material_ui: ^1.0.0
On a project still importing package:flutter/material.dart, pass
--material-import package:flutter/material.dart and the generated file will
use the old import instead. The generator itself is pure Dart and depends on
neither.
Install
As a dev dependency in the project you want to generate into:
dart pub add --dev figma_tokens_gen
Or add it to pubspec.yaml yourself. It is a build-time tool, so it belongs in
dev_dependencies — it never ships in your app:
dev_dependencies:
figma_tokens_gen: ^1.0.0
then:
dart pub get # or: flutter pub get
Or install it globally, to use across projects without adding a dependency:
dart pub global activate figma_tokens_gen
Use
dart run figma_tokens_gen --input tokens --output lib/generated/theme
| Option | Default | Meaning |
|---|---|---|
-i, --input |
tokens |
Directory (searched recursively) or a single JSON file |
-o, --output |
lib/generated/theme |
Directory the generated file is written to |
--class-name |
AppColors |
Name of the constants class |
--palette-class-name |
AppColorPalette |
Name of the palette-map class |
--file-name |
app_colors.dart |
Name of the generated file |
--material-import |
package:material_ui/material_ui.dart |
Import the generated file uses for Color |
--no-palettes |
(palettes on) | Skip the Map<String, Color> class |
-q, --quiet |
off | Suppress progress output |
Input
Every top-level object is a category; every object inside it is a token. Three value shapes are accepted, so you should not have to change your export settings:
{
"primary": {
"main": { "$value": { "hex": "#3B5BFF" }, "$type": "color" },
"light": { "$value": "#8FA3FF" },
"extraLight": "#E4E9FF"
}
}
- DTCG —
{"$value": ...}, the current format: the W3C draft that Figma's own variable export and recent Tokens Studio versions write - Legacy —
{"value": ...}, written by older Figma token plugins - Bare — the value directly
Both the current $-prefixed export and older exports work as-is, so upgrading
your Figma plugin does not require changing anything here — and the two shapes
can be mixed within a single file, which is what a partly re-exported token set
looks like in practice.
Colour values may be #RGB, #RGBA, #RRGGBB, #RRGGBBAA, a {"hex": ...}
map with an optional a field, or {"r":…, "g":…, "b":…, "a":…} channels in
either 0–1 or 0–255 form.
Non-colour tokens (spacing, typography) and plugin metadata keys ($extensions,
$themes, $metadata) are skipped.
Output
// GENERATED CODE - DO NOT MODIFY BY HAND
import 'package:material_ui/material_ui.dart';
abstract final class AppColors {
// primary
static const Color primaryMain = Color(0xFF3B5BFF);
static const Color primaryExtraLight = Color(0xFFE4E9FF);
}
/// The same tokens grouped by category, for lookup by name.
abstract final class AppColorPalette {
/// Tokens under the `primary` category.
static const Map<String, Color> primary = {
'main': Color(0xFF3B5BFF),
'extraLight': Color(0xFFE4E9FF),
};
}
Member names are category + Token in lowerCamelCase — primary/extraLight
becomes primaryExtraLight. Names that would collide with a Dart reserved word
get a trailing underscore; names starting with a digit get a $ prefix. Palette
map keys are strings, so they keep the token name as authored — a 500 token is
AppColorPalette.gray['500'].
The output contains no timestamp, so re-running the generator with unchanged tokens produces no diff.
Multiple files
When --input is a directory, every .json file under it is read in sorted
path order and merged. Categories combine; a token declared twice is taken from
the file that sorts last. Sorting is what makes the merge deterministic across
machines and CI.
Library API
Every stage is separately usable when the CLI is not enough — for example to fetch tokens over HTTP, or to emit a different shape of code:
import 'package:figma_tokens_gen/figma_tokens_gen.dart';
// Parse without touching the filesystem.
final tokens = const TokenParser().parseJson(jsonString);
print('${tokens.colorCount} colours in ${tokens.categories.length} categories');
// Emit with your own class names.
final source = const DartColorsEmitter(className: 'BrandColors').emit(tokens);
// Or run the whole pipeline.
final result = await TokenConverter().convert(
inputPath: 'tokens',
outputPath: 'lib/generated/theme',
);
To generate something other than a Flutter colour class — a ThemeExtension,
CSS variables, Compose tokens — implement TokenEmitter and pass it to
TokenConverter. The parser and CLI need no changes.
Wiring it into a build
Add it to whatever runs your codegen, next to build_runner:
dart run figma_tokens_gen -i tokens -o lib/generated/theme -q
dart format lib/generated/theme
Commit the generated file. Checking it in keeps builds reproducible and makes token changes visible in review.
License
MIT
Libraries
- figma_tokens_gen
- Generates Flutter
Colorconstants from Figma design-token JSON exports.