Tokens Studio(Figma) → Tailwind 동기화로 디자인 토큰을 Next.js에 붙이기

IT쿠키·2026년 2월 4일

1) 왜 이 방식이 필요한가?

디자인 시스템을 Figma에서 토큰으로 관리하면 장점이 많다.

  • 색상/타이포/스페이싱을 한 곳에서 관리
  • 개발에서는 text-primary, bg-brand 같은 semantic token으로 코딩
  • 토큰이 바뀌면 스크립트 한 번 실행해서 코드에 반영

문제는 “토큰을 어떻게 코드로 가져오느냐”인데,
여기서는 Tokens Studio export JSON(tokens.json)을 입력으로 받아서:

  • styles/design-tokens.ts (타입 안전 + 앱에서 사용)
  • styles/design-tokens.css (CSS 변수 + 유틸리티 클래스)

를 자동 생성한다.


2) 프로젝트 구성

예시 폴더 구조:

src/
  token/
    sync-tokens-studio.ts
styles/
  design-tokens.ts        (자동 생성)
  design-tokens.css       (자동 생성)
tokens.json               (Tokens Studio export)

package.json scripts:

{
  "scripts": {
    "sync:tokens": "node --import tsx src/token/sync-tokens-studio.ts"
  }
}

실행:

pnpm sync:tokens

3) Tokens Studio export 설정(중요)

Tokens Studio에서 Export할 때 권장:

  1. Figma에서 Tokens Studio 플러그인 열기
  2. 설정(⚙️) → Export
  3. Single file + All token sets
  4. Export → tokens.json 저장

스크립트는 입력 파일 후보 경로를 여러 개 탐색하도록 만들어둠
(tokens.json, ../tokens.json, ../../tokens.json 등)


4) 변환 스크립트 핵심 설계

4-1. 네이밍 컨벤션

  • 키는 kebab-case로 통일
  • 사이즈는 숫자 스케일 (space-16, font-size-12)
  • 색상은 semantic (text-primary, bg-brand)

스크립트의 normalizeKey()가 이 역할을 한다.

function normalizeKey(key: string): string {
  return key
    .replace(/[/:]/g, '-')
    .replace(/\s+/g, '-')
    .replace(/[()]/g, '')
    .replace(/-+/g, '-')
    .replace(/^-|-$/g, '')
    .toLowerCase();
}

4-2. 참조 토큰(resolve reference) 처리

Tokens Studio 토큰은 아래처럼 서로 참조하는 형태가 많다.

{
  "primary": { "$value": "{purple.500}", "$type": "color" }
}

이를 실제 값으로 풀어주는 로직이 resolveReference().

  • {...} 형태면 경로를 찾아 실제 값을 반환
  • 순환 참조는 경고로 막음
  • 못 찾으면 unresolvedRefs에 쌓아서 마지막에 출력

4-3. Primitive / Semantic 분리

Primitive: raw color 값(팔레트)
예: neutral.100, purple.500

Semantic: 의미 기반(개발에서 주로 사용)
예: text.primary, bg.brand, border.primary

결과 타입은 아래처럼 구성:

interface TailwindTokens {
  colors: {
    primitive: NestedColorMap;
    text: NestedColorMap;
    bg: NestedColorMap;
    border: NestedColorMap;
    icon: NestedColorMap;
  };
  spacing: Record<string, string>;
  container: Record<string, string>;
  fontSize: Record<string, string>;
  lineHeight: Record<string, string>;
  fontWeight: Record<string, string>;
  letterSpacing: Record<string, string>;
  borderRadius: Record<string, string>;
  borderWidth: Record<string, string>;
  typography: {
    heading: Record<string, TypographyPreset>;
    body: Record<string, TypographyPreset>;
  };
}

4-4. Dimension 토큰(스페이싱/폰트/보더 등)

Tokens Studio의 number / dimension 타입을 CSS 값으로 만든다.

  • 숫자면 기본 px를 붙임
  • fontWeight 같은 건 unit: null로 숫자 그대로 유지
function formatDimensionValue(value: string | number, options: { unit?: string | null } = {}) {
  if (typeof value === 'number') {
    if (options.unit === null) return String(value);
    return `${value}${options.unit ?? 'px'}`;
  }
  // ...
}

4-5. Typography preset(Heading/Body) 유틸 생성

Semantic Typography를 프리셋으로 뽑아서
.text-heading-4xl 같은 클래스를 자동 생성한다.

예:

.text-heading-4xl {
  font-size: 56px;
  line-height: 68px;
  letter-spacing: -0.2px;
  font-weight: 600;
}

이 방식은 “tailwind config에 다 때려넣기”보다:

  • 프리셋이 명시적이고
  • 디자이너와 협업할 때 의사소통이 쉽고
  • 유지보수가 덜 고통스럽다

5) 생성되는 결과물

5-1. styles/design-tokens.ts

  • designTokens 전체 export
  • semantic 색상(textColors, bgColors 등) 분리 export
  • tailwind config에 합칠 수 있는 tailwindColors 제공
export const tailwindColors = {
  text: textColors,
  bg: bgColors,
  border: borderColors,
  icon: iconColors,
  ...primitiveColors,
};

앱 코드에서 사용할 수도 있고:

import { textColors } from '@/styles/design-tokens';

const primary = textColors.primary; // "#18181b"

5-2. styles/design-tokens.css

CSS 변수 + 유틸리티 클래스가 함께 생성된다.

  • --color-text-primary
  • --spacing-space-16
  • .text-body-md, .container-960, .space-16

예:

@theme inline {
  --color-text-primary: #18181b;
  --spacing-space-16: 16px;
}

Tailwind v4를 쓰는 경우 @theme inline 컨셉과 잘 맞는다.


6) Next.js에 적용하기

6-1. globals.css에서 import

@import "./design-tokens.css";

프로젝트 구조에 따라:

  • src/styles/design-tokens.css면 경로만 맞춰주면 됨

6-2. 실제 사용 예시

(1) Typography preset

<h1 className="text-heading-3xl">제목</h1>
<p className="text-body-md">본문</p>

(2) Spacing 유틸(gap)

<div className="flex space-16">
  <div>left</div>
  <div>right</div>
</div>

(3) Container 유틸

<div className="container-960 mx-auto">
  ...
</div>

여기서 .container-960width:100% + max-width: 960px로 생성됨


7) 운영 팁 & 트러블슈팅

7-1. 오타 토큰 키는 미리 정리 추천

실제 토큰을 보면 sucess, transeparent, nomal 같은 키가 있다.
(스크립트는 그대로 kebab-case로 변환해서 내보내기 때문에)

  • 장기적으로는 Figma 쪽 키를 정리하는 게 베스트
  • 당장은 “기존 키를 그대로 써야 한다”면 스크립트는 그대로 유지하고
    앱 코드에서만 사용하는 키를 문서화하는 게 안전

7-2. 참조 해석 실패(unresolvedRefs)

실행 로그에 이런 게 뜨면:

⚠️  미해석 참조:
  - {foo.bar}
  • 토큰 JSON에 해당 경로가 있는지
  • set 구조(TokenStudio / Primitive: Color/Mode 1)가 바뀌지 않았는지
  • 대소문자/하이픈/공백 차이로 못 찾는 케이스가 없는지

를 확인한다.


7-3. “추출된 토큰이 너무 적습니다!” 경고

토큰이 10개 미만이면 구조가 바뀐 가능성이 높다.

  • Tokens Studio export 옵션 다시 확인
  • transformTokens()에서 찾는 키 경로를 최신 구조에 맞게 업데이트

8) 마무리

이 방식의 핵심은 하나다.

Figma 토큰을 소스 오브 트루스로 두고
코드는 자동 생성물로만 관리한다.

이렇게 해두면:

  • 색상/타입/스페이싱 변경이 “수작업”이 아니라 “동기화”가 되고
  • 개발/디자인 간 충돌이 확 줄어든다.

보너스: 추천 워크플로우

  1. 디자이너가 Tokens Studio에서 토큰 수정
  2. 개발자가 tokens.json export 반영
  3. pnpm sync:tokens
  4. PR에 styles/design-tokens.ts, styles/design-tokens.css 변경 포함
  5. 리뷰 포인트는 “토큰 변경이 의도한 게 맞는가?”로만 집중

원하면 다음 글로 이어서:

  • tailwind.config(또는 Tailwind v4 세팅)에 토큰을 더 깊게 연동하는 방법
  • 다크모드/테마(Mode 1/Mode 2)까지 확장하는 패턴
  • Tokens Studio를 Git으로 운영할 때 충돌 줄이는 방식

같은 것도 정리해줄게.

profile
IT 삶을 사는 쿠키

0개의 댓글