Style Dictionary v4 × Tailwind v4: 디자인 토큰을 유틸리티 클래스까지 자동 전파하는 단일 소스 파이프라인 구축
이 글의 대상 독자: Tailwind CSS를 실무에서 사용 중이며, 색상·간격·타이포그래피 등 디자인 토큰 관리에 어려움을 느끼는 프론트엔드 개발자를 대상으로 합니다. CSS 변수와 빌드 도구에 대한 기본 이해가 있으면 더 쉽게 따라오실 수 있습니다.
이 글에서 다루는 것 / 다루지 않는 것
✅ Style Dictionary v4로 DTCG 형식 토큰을
@layer tokensCSS로 출력하는 방법
✅ Tailwind v4@theme·@theme inline·@utility연동 패턴
✅ 다크모드 토큰 레이어 분리 패턴
✅ Tokens Studio(Figma) → Tailwind v4 전체 파이프라인
❌ Style Dictionary 기초 입문 (공식 문서 권장)
❌ Tailwind CSS 기본 사용법
❌ Figma·Tokens Studio 플러그인 설치·설정
디자인 시스템을 운영하다 보면 Figma의 색상 값이 CSS 변수에도, Tailwind 설정에도, 때로는 JS 상수에도 따로따로 흩어져 있는 상황을 마주치게 됩니다. 누군가 한 곳을 수정하면 나머지가 어긋나고, 색상뿐 아니라 간격·타이포그래피·그림자 토큰까지 동기화 누락이 쌓이면 결국 "토큰은 어디에 있는 게 맞는 건가?"라는 질문만 남습니다.
이 글을 마치면 pnpm build 한 번으로 Figma 색상이 bg-brand-primary Tailwind 유틸리티 클래스로 전파되는 단일 소스 파이프라인을 직접 구성할 수 있습니다. 2025년 1월 정식 출시된 Tailwind v4는 JavaScript 설정 파일 대신 CSS @theme 디렉티브로 토큰을 선언합니다. Style Dictionary v4 역시 ESM·DTCG 네이티브 지원으로 재탄생하면서, 두 도구의 방향이 CSS 변수라는 공통 언어로 수렴했습니다. 이 수렴 덕분에 이 글의 파이프라인은 별도 플러그인 없이도 구현 가능합니다.
핵심 개념
파이프라인 전체 흐름
글을 읽기 전에 전체 데이터 흐름을 먼저 파악하면 각 단계의 역할이 명확해집니다.
tokens/color.json sd.config.js dist/tokens.css globals.css
(DTCG JSON 토큰) → (Style Dictionary v4) → (@layer tokens 출력) → (@theme inline 연결)
↓
bg-brand-primary 등
Tailwind 유틸리티 자동 생성세 개의 핵심 기술이 각각 한 가지 책임을 담당합니다.
| 기술 | 책임 |
|---|---|
| Style Dictionary v4 | JSON 토큰 → CSS 변수 변환 (빌드 타임) |
CSS @layer |
토큰 변수와 Tailwind 내부 레이어 간 우선순위 격리 |
Tailwind v4 @theme |
CSS 변수 → 유틸리티 클래스 자동 생성 |
Style Dictionary v4: JSON 토큰을 CSS 변수로 변환하는 빌드 시스템
Style Dictionary는 디자인 토큰을 JSON으로 정의하면 CSS, iOS, Android 등 플랫폼별 코드로 변환해주는 빌드 시스템입니다. v4에서는 전체 코드베이스가 ESM으로 재작성되었고, W3C DTCG 스펙을 네이티브로 지원합니다.
// tokens/color.json (DTCG 형식)
{
"color": {
"brand": {
"primary": { "$value": "#0055FF", "$type": "color" },
"secondary": { "$value": "#00C2A8", "$type": "color" }
}
}
}DTCG(Design Tokens Community Group) — W3C 산하 커뮤니티 그룹으로, 디자인 토큰의 JSON 표현 방식을 표준화하는 스펙을 제정합니다.
$value,$type키 형식이 핵심이며, Style Dictionary v4는 이 형식을 그대로 인식합니다.
CSS Cascade Layers(@layer): 우선순위를 명시적으로 계층화
@layer는 CSS 규칙의 적용 순서를 선언적으로 제어하는 기능입니다. 같은 선택자를 가진 규칙이라도 레이어 선언 순서에 따라 우선순위가 결정되므로, 예측 불가능한 specificity 충돌을 방지할 수 있습니다.
/* 레이어 순서 선언: 나중에 선언된 레이어가 더 높은 우선순위 */
@layer tokens, base, components, utilities;Tailwind v4는 내부적으로 @layer theme, base, components, utilities를 공식 레이어 스택으로 채택했습니다. Style Dictionary 토큰을 별도의 @layer tokens에 격리하는 이유는 토큰 변수 정의가 Tailwind 유틸리티 규칙에 의해 의도치 않게 재정의되는 것을 막기 위해서입니다. tokens 레이어를 가장 먼저 선언하면 우선순위가 가장 낮아지므로, 토큰은 항상 "기반 값" 역할만 합니다.
Tailwind CSS v4: CSS-first 토큰 선언과 @theme 디렉티브
Tailwind v4의 가장 큰 변화는 tailwind.config.js를 CSS 파일로 대체한 것입니다. @theme 블록 안에 CSS 변수를 선언하면 Tailwind가 자동으로 유틸리티 클래스를 생성합니다.
@theme {
--color-brand-primary: #0055ff;
/* → bg-brand-primary, text-brand-primary, border-brand-primary 자동 생성 */
}
@theme inline— 일반@theme은 Tailwind가 선언된 변수를 내부--tw-*접두사로 복사합니다.@theme inline을 사용하면 이 복사를 생략하고 원본 변수를 그대로 참조합니다. 외부에서 이미 선언된 CSS 변수를 Tailwind 토큰으로 등록할 때 적합한 방식입니다.
실전 적용
예시 1: Style Dictionary → @layer tokens → Tailwind @theme 기본 연동
변수명 충돌 방지 전략
가장 먼저 해결해야 할 문제가 있습니다. Style Dictionary가 --color-brand-primary를 출력하고, @theme에서 그대로 --color-brand-primary: var(--color-brand-primary)로 참조하면 **CSS 자기 참조(circular reference)**가 발생해 값이 무효화됩니다.
해결 방법은 SD 출력 변수에 접두사를 부여해 이름을 구분하는 것입니다. 토큰 JSON의 최상위 키를 token으로 구성하면 자동으로 --token-color-brand-primary 형태로 출력됩니다.
// tokens/color.json — 최상위 키 'token'으로 접두사 자동 부여
{
"token": {
"color": {
"brand": {
"primary": { "$value": "#0055FF", "$type": "color" },
"secondary": { "$value": "#00C2A8", "$type": "color" }
}
},
"spacing": {
"4": { "$value": "1rem", "$type": "dimension" }
},
"font-size": {
"lg": { "$value": "1.125rem", "$type": "dimension" }
}
}
}1단계: Style Dictionary 설정 — @layer tokens 래핑 포맷
기본 css/variables 포맷은 @layer 래핑을 지원하지 않으므로, 커스텀 포맷으로 직접 래핑하는 방법이 가장 확실합니다.
// sd.config.js
import StyleDictionary from 'style-dictionary';
// @layer tokens로 출력을 감싸는 커스텀 포맷
StyleDictionary.registerFormat({
name: 'css/layer-tokens',
format: ({ dictionary, options }) => {
const selector = options.selector ?? ':root';
const vars = dictionary.allTokens
.map(token => ` ${token.name}: ${token.value};`)
.join('\n');
return `@layer tokens {\n ${selector} {\n${vars}\n }\n}\n`;
},
});
export default {
source: ['tokens/**/*.json'],
platforms: {
css: {
transformGroup: 'css',
prefix: 'token',
files: [
{
destination: 'dist/tokens.css',
format: 'css/layer-tokens',
options: {
selector: ':root',
outputReferences: true,
},
},
],
},
},
};
outputReferences: true— 토큰이 다른 토큰을 참조할 때("$value": "{color.brand.primary}"처럼), 값을 직접 복사하는 대신var(--token-color-brand-primary)형태의 CSS 변수 참조로 출력합니다. 런타임에서도 토큰 간 연결이 유지되어 동적 테마 전환이 가능해집니다.
출력 결과 (dist/tokens.css)
@layer tokens {
:root {
--token-color-brand-primary: #0055ff;
--token-color-brand-secondary: #00c2a8;
--token-spacing-4: 1rem;
--token-font-size-lg: 1.125rem;
}
}2단계: Tailwind CSS 진입점에서 연결
/* src/globals.css */
@import "tailwindcss";
@import "../dist/tokens.css";
/* 레이어 우선순위 명시적 선언 (항상 최상단에 위치) */
@layer tokens, base, components, utilities;
@theme inline {
/* SD 접두사 변수 → Tailwind 토큰으로 매핑 (자기 참조 없음) */
--color-brand-primary: var(--token-color-brand-primary);
--color-brand-secondary: var(--token-color-brand-secondary);
--spacing-4: var(--token-spacing-4);
--font-size-lg: var(--token-font-size-lg);
}| 구문 | 역할 |
|---|---|
@import "tailwindcss" |
Tailwind v4 레이어 스택 전체 주입 |
@import "../dist/tokens.css" |
Style Dictionary 출력 CSS 변수 로드 |
@layer tokens, base, components, utilities |
레이어 우선순위 명시 (tokens가 가장 낮음) |
@theme inline |
원본 CSS 변수를 복사 없이 Tailwind 토큰으로 등록 |
이 설정만으로 bg-brand-primary, text-brand-secondary, p-4 같은 Tailwind 유틸리티 클래스가 자동으로 사용 가능해집니다.
3단계: package.json 빌드 스크립트 연결
// package.json
{
"scripts": {
"build:tokens": "style-dictionary build --config sd.config.js",
"build:css": "tailwindcss -i src/globals.css -o dist/output.css",
"build": "pnpm build:tokens && pnpm build:css"
}
}pnpm build 한 번으로 토큰 빌드 → CSS 생성이 순서대로 실행됩니다.
예시 2: 다크모드 토큰 레이어 분리 패턴
라이트/다크 모드 토큰을 같은 @layer tokens 안에서 셀렉터로 분리하면 Tailwind의 dark: 변형과 자연스럽게 연동됩니다.
Style Dictionary 설정
// sd.config.js — 라이트/다크 파일 분리 출력
StyleDictionary.registerFormat({
name: 'css/layer-tokens',
format: ({ dictionary, options }) => {
const selector = options.selector ?? ':root';
const vars = dictionary.allTokens
.map(token => ` ${token.name}: ${token.value};`)
.join('\n');
return `@layer tokens {\n ${selector} {\n${vars}\n }\n}\n`;
},
});
export default {
source: ['tokens/**/*.json'],
platforms: {
css: {
transformGroup: 'css',
prefix: 'token',
files: [
{
destination: 'dist/tokens.css',
format: 'css/layer-tokens',
filter: token => !token.filePath.includes('dark'),
options: { selector: ':root' },
},
{
destination: 'dist/tokens-dark.css',
format: 'css/layer-tokens',
filter: token => token.filePath.includes('dark'),
options: { selector: '[data-theme="dark"]' },
},
],
},
},
};출력 결과
/* dist/tokens.css */
@layer tokens {
:root {
--token-color-bg: #ffffff;
--token-color-text: #111111;
}
}/* dist/tokens-dark.css */
@layer tokens {
[data-theme="dark"] {
--token-color-bg: #111111;
--token-color-text: #f5f5f5;
}
}Tailwind 연결
/* src/globals.css */
@import "tailwindcss";
@import "../dist/tokens.css";
@import "../dist/tokens-dark.css";
@layer tokens, base, components, utilities;
@theme inline {
--color-bg: var(--token-color-bg);
--color-text: var(--token-color-text);
}<html> 태그에 data-theme="dark" 속성을 토글하면 CSS 변수가 즉시 교체되고, getComputedStyle()로도 현재 테마 색상을 JS에서 읽을 수 있어 동적 테마 전환에 유용합니다.
예시 3: @utility로 토큰 기반 커스텀 유틸리티 작성
Tailwind v4의 @utility 디렉티브를 사용하면 JS 플러그인 없이 CSS 레벨에서 토큰 기반 커스텀 유틸리티를 만들 수 있습니다.
/* src/globals.css */
@utility btn-primary {
background-color: var(--token-color-brand-primary);
color: var(--token-color-white);
padding: var(--token-spacing-2) var(--token-spacing-4);
border-radius: var(--token-radius-md);
font-weight: 600;
}
@utility btn-secondary {
background-color: var(--token-color-brand-secondary);
color: var(--token-color-white);
padding: var(--token-spacing-2) var(--token-spacing-4);
border-radius: var(--token-radius-md);
}hover:btn-primary, dark:btn-primary, focus:btn-secondary처럼 Tailwind의 모든 변형(variants)이 자동으로 지원됩니다. @apply보다 성능 오버헤드가 적고 Tailwind v4 팀이 권장하는 방식입니다.
예시 4: Tokens Studio → Style Dictionary v4 → Tailwind v4 전체 파이프라인 (선택적 심화)
이 예시는 Figma + Tokens Studio 플러그인을 사용하는 팀을 위한 심화 내용입니다. Figma를 사용하지 않는다면 예시 1–3만으로 충분합니다.
@tokens-studio/sd-transforms 패키지를 추가하면 Figma에서 내보낸 JSON을 Style Dictionary가 바로 처리할 수 있습니다.
pnpm add -D style-dictionary @tokens-studio/sd-transforms// sd.config.js — Tokens Studio 전체 파이프라인
import StyleDictionary from 'style-dictionary';
import { registerTransforms } from '@tokens-studio/sd-transforms';
// StyleDictionary 인스턴스에 Tokens Studio 전처리 transform 등록
registerTransforms(StyleDictionary);
StyleDictionary.registerFormat({
name: 'css/layer-tokens',
format: ({ dictionary, options }) => {
const selector = options.selector ?? ':root';
const vars = dictionary.allTokens
.map(token => ` ${token.name}: ${token.value};`)
.join('\n');
return `@layer tokens {\n ${selector} {\n${vars}\n }\n}\n`;
},
});
export default {
source: ['tokens/**/*.json'],
platforms: {
css: {
transformGroup: 'tokens-studio',
prefix: 'token',
files: [
{
destination: 'dist/tokens.css',
format: 'css/layer-tokens',
options: {
selector: ':root',
outputReferences: true,
},
},
],
},
},
};tokens-studio/sd-tailwindv4 레퍼런스 구현(GitHub)이 이 파이프라인의 공식 예제입니다. Figma → JSON 내보내기 → CSS 변수 → Tailwind 유틸리티 클래스까지의 전 과정이 pnpm build 한 번으로 완료됩니다.
※ 이미 작성된 관련 포스트: 「Tokens Studio로 멀티브랜드 × 다크모드 디자인 토큰을 하나의 파이프라인에서 자동화하기 — Style Dictionary와 permutateThemes 완전 활용 가이드」
장단점 분석
장점
| 항목 | 내용 |
|---|---|
| 단일 소스 관리 | 토큰 JSON 하나를 수정하면 CSS 변수, Tailwind 유틸리티, JS 상수가 모두 자동 갱신됩니다 |
| 캐스케이드 예측성 | @layer 덕분에 토큰 변수가 유틸리티에 덮어씌워지는 specificity 충돌이 사라집니다 |
| 런타임 접근성 | CSS 변수는 getComputedStyle()로 JS에서 읽을 수 있어 동적 테마 전환이 간단해집니다 |
| 프레임워크 독립성 | Style Dictionary 출력물은 Tailwind 외에 다른 프레임워크나 vanilla CSS에도 재사용 가능합니다 |
@property 타입 안전성 |
CSS 변수에 타입을 등록해 트랜지션·애니메이션 보간 예측 가능성이 높아집니다 |
단점 및 주의사항
| 항목 | 내용 | 대응 방안 |
|---|---|---|
| 초기 설정 복잡도 | SD 설정, 포맷 커스터마이즈, Tailwind @theme 매핑이 겹쳐 학습 비용이 높습니다 |
tokens-studio/sd-tailwindv4 레퍼런스 구현을 스타터로 활용하는 것을 권장합니다 |
| 변수 이름 전략 필요 | SD 출력 변수명과 Tailwind 토큰 변수명이 같으면 자기 참조 오류가 발생합니다 | SD prefix 설정 또는 최상위 키 네이밍으로 변수명을 구분하는 것이 좋습니다 |
@apply 남용 위험 |
Tailwind v4 팀은 @apply 남용을 공식적으로 경고합니다 |
@utility 디렉티브와 CSS 변수 직접 사용으로 전환하는 것을 권장합니다 |
| 빌드 파이프라인 의존 | Figma 변경 → SD 빌드 → Tailwind 재생성까지 CI 파이프라인 연결이 필요합니다 | GitHub Actions 등 CI에 pnpm build 스텝을 추가하면 자동화됩니다 |
| 레이어 순서 관리 | @layer 순서 선언 누락 시 import 순서에 따라 우선순위가 달라질 수 있습니다 |
CSS 파일 최상단에 @layer tokens, base, components, utilities;를 항상 명시하는 것을 권장합니다 |
| 브라우저 지원 | @layer는 Chrome 99+, Firefox 97+, Safari 15.4+부터 지원됩니다 |
IE 지원이 필요한 프로젝트에는 적용이 어렵습니다 |
@property— CSS 변수의 타입, 초기값, 상속 여부를 브라우저에 등록하는 CSS 규칙입니다.@property --color-brand-primary { syntax: '<color>'; inherits: true; initial-value: #0055ff; }처럼 선언하면 해당 변수가 트랜지션·애니메이션에서도 올바르게 보간됩니다.
실무에서 가장 흔한 실수
-
SD 출력 변수명과 Tailwind 토큰 변수명을 동일하게 사용하는 것 —
--color-brand-primary: var(--color-brand-primary)는 CSS 순환 참조로 처리되어 값이 무효화됩니다. SD prefix 설정 또는 최상위 키 구조로--token-color-brand-primary처럼 이름을 구분하는 것이 필수입니다. -
@layer순서를 CSS 파일 최상단에 선언하지 않는 것 —@layer순서 선언이 없으면 각@layer블록이 처음 등장하는 순서가 우선순위가 되어 import 순서에 따라 스타일이 달라집니다.globals.css최상단에@layer tokens, base, components, utilities;를 반드시 선언하는 것을 권장합니다. -
Style Dictionary 변수명을 camelCase로 출력하는 것 — SD 기본 설정에 따라
--color-brandPrimary로 출력되면 Tailwind가bg-brandPrimary클래스를 생성해 컨벤션이 어긋납니다. SD 설정에서transformGroup: 'css'를 사용하거나name/kebabtransform을 명시적으로 적용해 kebab-case(bg-brand-primary)를 유지하는 것이 좋습니다.
마치며
Style Dictionary v4의 @layer tokens 출력과 Tailwind v4의 @theme inline 연동은, JSON 토큰 하나의 변경이 CSS 변수와 유틸리티 클래스까지 동시에 전파되는 진정한 단일 소스 파이프라인을 가능하게 합니다.
지금 바로 시작해볼 수 있는 3단계:
-
pnpm add -D style-dictionary를 실행한 뒤, 프로젝트의 기존 색상 토큰 몇 개를tokens/color.json에 DTCG 형식($value,$type)으로 옮겨보실 수 있습니다.package.json에"build:tokens": "style-dictionary build --config sd.config.js"스크립트를 추가하고pnpm build:tokens로 첫 CSS 변수 출력을 확인해 보시면 좋습니다. -
출력된
dist/tokens.css를globals.css에@import로 추가하고, 예시 1의@theme inline블록(SD 접두사 변수 → Tailwind 토큰 매핑)을 작성해보실 수 있습니다. 브라우저 DevTools의 Elements 탭에서bg-brand-primary클래스가 자동 생성되는 것을 확인하실 수 있습니다. -
팀이 Figma를 사용한다면
pnpm add -D @tokens-studio/sd-transforms를 추가해 Tokens Studio JSON을 직접 파이프라인에 연결하는 것을 권장합니다.tokens-studio/sd-tailwindv4GitHub 레퍼런스 구현을 스타터 템플릿으로 활용하시면 설정 시간을 크게 줄이실 수 있습니다.
다음 글: CSS
@property로 디자인 토큰에 타입을 등록하고 트랜지션·애니메이션까지 안전하게 제어하는 방법 — Style Dictionary v4와 Tailwind v4에서의 실전 적용 가이드
참고 자료
- Style Dictionary 공식 문서 | styledictionary.com
- Style Dictionary v4 Migration Guidelines | styledictionary.com
- Style Dictionary Built-in Formats | styledictionary.com
- tokens-studio/sd-tailwindv4 레퍼런스 구현 | GitHub
- tokens-studio/sd-transforms | GitHub
- style-dictionary-utils | npm
- Tailwind CSS v4.0 공식 릴리스 노트 | tailwindcss.com
- Tailwind CSS Functions and Directives | tailwindcss.com
- Tailwind CSS Adding Custom Styles | tailwindcss.com
- Using CSS Cascade Layers With Tailwind Utilities | CSS-Tricks
- The CSS / Utility hybrid approach with Tailwind v4 | This Dot Labs
- Design Tokens That Scale in 2026 (Tailwind v4 + CSS Variables) | Mavik Labs