Figma Variables API + sd-transforms: Design Token CI/CD로 디자이너 변경을 Git PR로 자동화하기
디자이너가 Figma에서 색상 하나 바꿨는데, 개발자가 그걸 몰라서 일주일 뒤에 "어? 이거 왜 다른 색이에요?"라는 상황 — 한 번쯤 겪어보셨죠? 저도 처음엔 그냥 Slack으로 공유해달라고 부탁하고, Jira 티켓 달아달라고 하고, 온갖 수동 프로세스를 붙여봤는데 결국 어딘가에서 항상 새고 있더라고요. 디자인 시스템을 운영하는 팀이라면 이 문제를 구조적으로 해결하고 싶다는 욕구가 생길 수밖에 없습니다.
이 글에서는 Figma Variables REST API와 Tokens Studio sd-transforms를 연결해, 디자이너의 Figma 변경이 자동으로 GitHub PR을 만들고 토큰 빌드 파이프라인까지 실행되는 Design Token CI/CD를 구축하는 방법을 다룹니다. 단순한 개념 소개가 아니라, 실제로 동작하는 코드와 함께 각 조각이 어떻게 맞물리는지 보여드리려고 합니다. 대상은 디자인 시스템이나 CI/CD 경험이 있는 프론트엔드 개발자 기준으로 설명 깊이를 맞췄습니다.
한 가지 미리 말씀드리고 싶은 게 있는데요 — Figma Variables REST API의 읽기/쓰기 기능은 Enterprise 플랜에서만 사용 가능합니다. Professional 플랜 이하라면 전체 파이프라인을 완성하기 어렵고, Tokens Studio 플러그인의 직접 Push 방식으로 우회하는 게 현실적입니다. 플랜 확인부터 먼저 해두시면 뒤에서 막히는 일이 없을 겁니다.
핵심 개념
두 가지 아키텍처 선택지
파이프라인을 구축하기 전에, 어떤 경로로 갈지 먼저 선택하는 편이 좋습니다. 크게 두 가지 방식이 있고, 팀 상황에 따라 시작점이 달라집니다.
| 방식 | 흐름 | 전제 조건 |
|---|---|---|
| Webhook 자동화 | Figma 라이브러리 게시 → Webhook → 수신 서버 → GitHub Actions → PR | Enterprise 플랜 + 수신 서버 |
| Plugin 직접 Push | 디자이너 "Push Changes" 클릭 → GitHub 커밋 → GitHub Actions → PR | 모든 플랜 가능, 디자이너 수동 조작 필요 |
Enterprise 플랜이 없다면 Plugin 직접 Push 방식으로 파이프라인의 절반 이상을 구축해볼 수 있습니다. 이 글에서는 Webhook 자동화 방식을 중심으로 설명하고, Plugin 방식은 대안으로 함께 다룹니다.
Figma Variables REST API — 변수를 코드로 꺼내오는 창구
Figma Variables는 2023년에 출시된 기능으로, 색상·타이포그래피·간격 같은 디자인 값을 Figma 내부에서 구조화된 변수로 관리할 수 있게 해줍니다. REST API로 이 변수들을 외부에서 읽고 쓸 수 있는데, 엔드포인트 자체는 단순합니다.
GET https://api.figma.com/v1/files/:file_key/variables/local
X-Figma-Token: your_personal_access_token이 JSON을 직접 보면 처음엔 좀 복잡해 보이는데, 핵심은 컬렉션·모드·값 세 가지입니다.
{
"meta": {
"variableCollections": {
"VariableCollectionId:1:1": {
"id": "VariableCollectionId:1:1",
"name": "Colors",
"modes": [
{ "modeId": "1:0", "name": "Light" },
{ "modeId": "1:1", "name": "Dark" }
],
"defaultModeId": "1:0"
}
},
"variables": {
"VariableID:1:2": {
"id": "VariableID:1:2",
"name": "color/primary",
"resolvedType": "COLOR",
"valuesByMode": {
"1:0": { "r": 0, "g": 0.4, "b": 1, "a": 1 },
"1:1": { "r": 0.1, "g": 0.5, "b": 1, "a": 1 }
}
}
}
}
}이 응답을 W3C DTCG 포맷의 토큰 JSON으로 파싱·변환하면 Style Dictionary가 소화할 수 있는 형태가 됩니다. 실제 변환 로직의 레퍼런스로는 Figma 공식 저장소 figma/variables-github-action-example의 src/token-export.ts를 먼저 보시는 걸 추천드립니다. 색상 rgba → hex 변환, 모드별 분기 처리가 실제 코드로 잘 정리되어 있습니다.
Tokens Studio와 sd-transforms — 토큰의 통역사
Tokens Studio는 Figma 플러그인인데, Figma Variables를 디자인 토큰 JSON으로 내보내거나 가져오고, GitHub 같은 Git 저장소와 직접 동기화하는 브릿지 역할을 합니다. 디자이너 입장에서는 "Push Changes" 버튼 하나로 GitHub 브랜치에 커밋이 올라가는 경험을 하게 됩니다.
@tokens-studio/sd-transforms 는 Tokens Studio가 내보낸 토큰을 Style Dictionary가 이해할 수 있도록 변환해주는 어댑터 패키지입니다. 솔직히 처음 설정할 때 이 두 도구의 역할 분리가 헷갈렸는데, 쉽게 정리하면 이렇습니다.
| 도구 | 역할 |
|---|---|
| Tokens Studio | Figma ↔ Git 동기화 (토큰 원본 관리) |
| sd-transforms | Tokens Studio 포맷 → Style Dictionary 호환 포맷 변환 |
| Style Dictionary | 토큰 JSON → CSS/SCSS/iOS/Android 등 플랫폼별 출력 |
W3C DTCG 포맷 — 도구를 초월하는 표준
W3C Design Tokens Community Group의 첫 안정 스펙(2025.10)이 2025년 10월에 공개되었고, Figma·Penpot·Sketch 등 주요 도구들이 채택하고 있습니다. sd-transforms도 현재 이 스펙의 $value/$type 프로퍼티 기반 변환을 기본 지원하며, 레거시 포맷과 DTCG 포맷을 플러그인 설정으로 전환할 수 있습니다.
{
"color": {
"primary": {
"$value": "#0066FF",
"$type": "color",
"$description": "브랜드 주요 색상"
}
}
}DTCG(Design Tokens Community Group): W3C 산하 커뮤니티 그룹으로, 디자인 도구 간 토큰 교환을 위한 표준 JSON 포맷을 정의합니다.
$value,$type같은 달러 접두사 프로퍼티가 특징입니다.
실전 적용
예시 1: Figma Webhook → Node.js 수신 서버 → GitHub Actions 트리거
디자이너가 Figma 라이브러리를 게시(Publish)하면 LIBRARY_PUBLISH Webhook 이벤트가 발화됩니다. 이 이벤트를 받아서 GitHub Actions를 트리거하는 중간 서버가 필요합니다. Vercel Functions나 AWS Lambda 같은 서버리스로 구성하면 운영 부담을 많이 줄일 수 있습니다.
// webhook-receiver.ts (Express 기반)
import express from 'express';
import { Octokit } from '@octokit/rest';
const app = express();
app.use(express.json());
// Octokit: GitHub API 공식 SDK
const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
app.post('/figma-webhook', async (req, res) => {
// passcode 검증 — 이걸 빠뜨리면 외부에서 임의로 Actions를 트리거할 수 있습니다
const passcode = req.headers['x-figma-passcode'];
if (passcode !== process.env.FIGMA_WEBHOOK_PASSCODE) {
return res.sendStatus(401);
}
const { event_type, file_key } = req.body;
if (event_type !== 'LIBRARY_PUBLISH') {
return res.sendStatus(200);
}
await octokit.actions.createWorkflowDispatch({
owner: process.env.GITHUB_OWNER!,
repo: process.env.GITHUB_REPO!,
workflow_id: 'sync-tokens.yml',
ref: 'main',
inputs: { figma_file_key: file_key }
});
res.sendStatus(200);
});| 코드 포인트 | 설명 |
|---|---|
x-figma-passcode 검증 |
Figma가 Webhook 등록 시 설정한 passcode를 헤더로 보냅니다. 이 검증이 없으면 누구든 엔드포인트를 호출해 Actions를 트리거할 수 있습니다 |
event_type !== 'LIBRARY_PUBLISH' |
라이브러리 게시 이벤트만 필터링해 불필요한 Actions 실행을 방지합니다 |
workflow_dispatch |
외부에서 GitHub Actions 워크플로를 수동으로 트리거하는 API입니다 |
figma_file_key |
이후 Figma Variables API 호출에 필요한 파일 식별자입니다 |
Figma Webhook 등록도 필요합니다. REST API로 등록할 수 있습니다.
curl -X POST "https://api.figma.com/v2/webhooks" \
-H "X-Figma-Token: $FIGMA_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"event_type": "LIBRARY_PUBLISH",
"team_id": "YOUR_TEAM_ID",
"endpoint": "https://your-server.com/figma-webhook",
"passcode": "YOUR_SECRET_PASSCODE"
}'예시 2: GitHub Actions로 Figma Variables Fetch → 토큰 빌드 → PR 생성
트리거가 발화되면 GitHub Actions에서 실제 작업이 일어납니다. Figma Variables를 가져와서 sd-transforms로 변환하고, PR까지 자동 생성하는 워크플로입니다.
# .github/workflows/sync-tokens.yml
name: Sync Design Tokens
on:
push:
paths: ['tokens/**']
workflow_dispatch:
inputs:
figma_file_key:
type: string
description: Figma 파일 키
jobs:
sync-and-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Fetch Figma Variables
# workflow_dispatch로 트리거된 경우에만 Figma API 호출
if: ${{ github.event_name == 'workflow_dispatch' && inputs.figma_file_key != '' }}
run: |
curl -s \
-H "X-Figma-Token: ${{ secrets.FIGMA_TOKEN }}" \
"https://api.figma.com/v1/files/${{ inputs.figma_file_key }}/variables/local" \
> tokens/figma-variables.json
- uses: pnpm/action-setup@v4
with:
version: 9
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'pnpm'
- run: pnpm install --frozen-lockfile
- name: Transform Tokens
run: pnpm run build:tokens
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
with:
title: "🎨 Sync Design Tokens from Figma"
branch: "chore/sync-tokens-${{ github.run_number }}"
commit-message: "chore: sync design tokens from Figma variables"
body: |
Figma Variables 변경이 감지되어 자동으로 생성된 PR입니다.
변경 내용을 확인 후 머지해 주세요.
peter-evans/create-pull-request: GitHub Actions에서 파일 변경을 감지해 자동으로 PR을 생성해주는 Action입니다. 브랜치 생성·커밋·PR 오픈을 한 스텝에 처리해 파이프라인 구성이 단순해집니다.
push 이벤트로 트리거될 때는 inputs.figma_file_key가 비어있어서 Figma API 호출이 실패합니다. if 조건으로 이벤트 타입을 분기해두는 게 핵심입니다.
예시 3: sd-transforms + Style Dictionary 변환 스크립트
GitHub Actions에서 pnpm run build:tokens가 실행할 스크립트입니다. Tokens Studio 포맷의 JSON을 받아 CSS Variables, SCSS 변수 등으로 변환합니다.
sd-transforms v1 이상에서는 API 사용 방식이 변경되었습니다. registerTransforms + usesSD3: true 옵션을 함께 사용하는 게 현재 권장 방식입니다.
// build-tokens.mjs
import StyleDictionary from 'style-dictionary';
import { registerTransforms } from '@tokens-studio/sd-transforms';
// sd-transforms v1 기준: usesSD3: true 옵션과 함께 사용
registerTransforms(StyleDictionary, { usesSD3: true });
const sd = new StyleDictionary({
source: ['tokens/**/*.json'],
platforms: {
css: {
transformGroup: 'tokens-studio',
transforms: ['name/kebab'], // transformGroup 위에 추가할 transform만 지정
buildPath: 'dist/',
files: [
{
destination: 'variables.css',
format: 'css/variables',
options: {
outputReferences: true // 참조 관계를 CSS var()로 유지
}
}
]
},
js: {
transformGroup: 'tokens-studio',
buildPath: 'dist/',
files: [
{
destination: 'tokens.js',
format: 'javascript/es6'
}
]
}
}
});
await sd.buildAllPlatforms();outputReferences: true 옵션이 중요합니다. 이 옵션이 있으면 토큰 간 참조 관계가 CSS var() 함수로 그대로 유지되어, 테마 스위칭 같은 시나리오에서 CSS Custom Properties의 동적 특성을 살릴 수 있습니다. 저도 처음에 이 옵션 없이 빌드했다가 다크모드 전환이 안 되는 상황을 겪었는데, 나중에 원인을 찾고 나서야 처음 설정이 얼마나 중요한지 실감했습니다.
예시 4: Tokens Studio Plugin 직접 Push 방식 (서버 없이)
Webhook 서버 운영이 부담스럽거나 Enterprise 플랜이 없는 상황이라면, 디자이너가 Tokens Studio 플러그인에서 직접 GitHub에 Push하는 방식이 현실적인 대안입니다.
[디자이너 → Tokens Studio "Push Changes" 클릭]
→ GitHub 브랜치에 tokens/*.json 커밋
→ GitHub Actions push 이벤트 트리거 (paths: ['tokens/**'])
→ sd-transforms + Style Dictionary 실행
→ PR 자동 생성서버 없이도 파이프라인의 핵심 부분이 동작합니다. 다만 디자이너가 플러그인 조작을 직접 해야 한다는 점에서 Webhook 방식보다 자동화 수준이 낮고, 디자이너가 Push를 잊거나 늦게 하면 그만큼 동기화가 늦어집니다.
장단점 분석
장점
| 항목 | 내용 |
|---|---|
| 단일 진실 원천 | Figma Variables가 디자인·코드 토큰의 유일한 소스가 되어 불일치 문제가 구조적으로 해소됩니다 |
| 자동화된 핸드오프 | 디자이너의 Figma 변경이 코드 PR로 즉시 반영되어 수동 커뮤니케이션이 줄어듭니다 |
| 버전 관리 | Git 히스토리로 모든 토큰 변경 이력을 추적할 수 있습니다 |
| 플랫폼 독립성 | Style Dictionary로 Web/iOS/Android 결과물을 동시에 생성할 수 있습니다 |
| W3C 표준 준수 | DTCG 포맷 덕분에 도구 간 이식성이 확보됩니다 |
단점 및 주의사항
저희 팀에서 실제로 가장 당황했던 부분은 토큰 네이밍 충돌이었는데요, 처음부터 규칙을 못 박아두지 않으면 나중에 수습하기가 꽤 번거롭습니다.
| 항목 | 내용 | 대응 방안 |
|---|---|---|
| Enterprise 플랜 필수 | Figma Variables REST API는 Enterprise에서만 읽기/쓰기 가능 | Professional 플랜은 Tokens Studio Plugin 직접 Push 방식으로 대체 가능 |
| Webhook 서버 운영 | LIBRARY_PUBLISH 수신용 별도 서버 또는 서버리스 함수 필요 | Vercel Functions(/api/figma-webhook), AWS Lambda 등으로 서버리스 구성하면 관리 포인트를 줄일 수 있습니다 |
| 토큰 네이밍 의존성 | sd-transforms가 Tokens Studio의 네이밍 컨벤션을 전제로 동작 | 파이프라인 구축 전에 디자인·개발팀이 네이밍 규칙을 먼저 문서화하는 것을 권장드립니다 |
| 양방향 충돌 위험 | 코드→Figma 방향 동기화 시 변수 삭제 미지원 | sd-transforms의 코드→Figma 동기화는 이름이 일치하는 변수만 추가·수정하고, 삭제는 하지 않는 보수적인 방식으로 동작합니다. 코드에서 변수를 지워도 Figma에 남아있는 경우가 생기므로, 코드→Figma 방향은 추가/수정만 허용하는 정책으로 운영하는 게 안전합니다 |
| Rate Limit | Figma REST API는 분당 요청 수 제한 존재 | 변경 이벤트 디바운싱, 캐싱 레이어 도입 |
| DTCG 전환 비용 | 기존 레거시 토큰 포맷을 DTCG로 마이그레이션해야 할 수 있음 | TokensBrücke 플러그인으로 일괄 변환 후 점진적 마이그레이션 |
실무에서 가장 흔한 실수
-
Figma Webhook의
passcode검증을 생략하는 경우 — 수신 서버에서X-Figma-Passcode헤더를 검증하지 않으면 외부에서 임의로 Actions를 트리거할 수 있습니다. 앞서 예시 1의 코드처럼 passcode 일치 여부를 반드시 확인하는 로직을 포함하는 것이 좋습니다. -
outputReferences옵션을 끄고 모든 값을 하드코딩하는 경우 — 참조 구조가 평탄화되어 버리면 CSS Custom Properties의 동적 테마 스위칭이 불가능해집니다. 토큰 간 참조(예:semantic.color.primary가primitive.blue.500을 참조)가 있다면 이 옵션은 켜두는 편이 좋습니다. -
토큰 네이밍 규칙을 디자인·개발팀이 따로 관리하는 경우 — Tokens Studio의 네이밍 컨벤션과 코드베이스의 CSS 클래스 네이밍이 충돌하면 sd-transforms 변환 결과가 예상과 달라집니다. 파이프라인 구축 전에 네이밍 규칙을 팀 공통으로 먼저 정리해두는 것이 나중의 수고를 덜어줍니다.
마치며
글 첫머리에서 꺼냈던 그 상황 — "어? 이거 왜 다른 색이에요?" — 이 파이프라인이 완성되고 나면 그런 대화가 많이 줄어듭니다. Figma Variables REST API와 sd-transforms를 연결하면, 디자인 변경이 코드로 흘러가는 과정의 수동 작업과 불일치 문제를 구조적으로 해소할 수 있습니다.
전체를 한 번에 구축하려 하기보다, 아래 단계로 나눠서 시작해보시면 훨씬 수월합니다.
상황에 따른 3단계 시작점:
-
Tokens Studio 플러그인 설치 후 GitHub 연동 확인 (소요 시간: 30분~1시간 / 필요 조건: 모든 플랜) — 플러그인 설정에서 GitHub Personal Access Token과 저장소 정보를 입력하면 "Push Changes" 버튼으로
tokens/*.json이 커밋되는지 확인해볼 수 있습니다. Webhook 서버 없이도 파이프라인의 절반이 동작하는 걸 바로 체감할 수 있어서, 저도 이 순서로 먼저 검증했습니다. -
build-tokens.mjs와sync-tokens.yml추가 (소요 시간: 1~2시간 / 필요 조건: 모든 플랜) —pnpm add -D @tokens-studio/sd-transforms style-dictionary로 의존성을 설치하고, 예시 3의 스크립트를pnpm run build:tokens로 연결한 뒤peter-evans/create-pull-requestAction을 붙이면 PR 자동 생성까지 확인해볼 수 있습니다. -
Figma Webhook 등록 + Vercel Functions 수신 서버 배포 (소요 시간: 반나절 / 필요 조건: Enterprise 플랜) — 예시 1의 수신 서버 코드를 Vercel에 올리고, Figma REST API로
LIBRARY_PUBLISHWebhook을 등록하면 디자이너의 라이브러리 게시가 자동으로 PR을 만드는 Full-Automation 파이프라인이 완성됩니다.
다음 글: Style Dictionary의
outputReferences와 CSS Custom Properties를 활용해 런타임 테마 스위칭(다크모드·브랜드 테마)을 토큰 파이프라인과 연결하는 방법을 다뤄볼 예정입니다.
참고 자료
- Figma Variables REST API 공식 문서
- Figma Webhooks V2 공식 문서
- figma/variables-github-action-example (공식 GitHub)
- Tokens Studio GitHub Sync 공식 문서
- Tokens Studio + GitHub Actions 공식 가이드
- tokens-studio/sd-transforms GitHub
- Style Dictionary + SD Transforms | Tokens Studio 문서
- Token Format - W3C DTCG vs Legacy | Tokens Studio 문서
- Syncing Figma variables with Design Tokens - Nate Baldwin (Medium)
- Automating design systems with Figma Variables REST API - Medium
- Building a Figma to GitHub token pipeline - DEV Community
- Advanced Figma Webhook Integration - Poespas Blog (2025)
- Syncing Figma Variables with GitHub Actions - James Ives
- GitFig - Figma Variables ↔ GitHub 동기화 도구
- From Figma to npm Package: Automate Your Design Tokens Pipeline