Tailwind CSS v3에서 v4로의 마이그레이션 가이드 — 주요 변경사항, 자동 마이그레이션 도구, 단계별 전환 전략, 그리고 흔한 문제 해결법을 다룹니다.
10장에서 디자인 시스템 구축을 다뤘습니다. 이 마지막 장에서는 기존 Tailwind CSS v3 프로젝트를 v4로 마이그레이션하는 실전 가이드를 제공합니다. 자동 마이그레이션 도구, 주요 변경사항, 단계별 전환 전략, 그리고 흔히 마주치는 문제와 해결법을 다룹니다.
Tailwind 팀은 공식 마이그레이션 도구를 제공합니다. 대부분의 변경사항을 자동으로 처리합니다.
npx @tailwindcss/upgrade@latest이 도구는 다음을 자동으로 처리합니다.
tailwindcss, PostCSS 플러그인 등)tailwind.config.js의 설정을 CSS @theme으로 변환@tailwind 디렉티브를 @import "tailwindcss"로 변환자동 마이그레이션 도구를 실행하기 전에 반드시 Git에 현재 상태를 커밋하세요. 도구가 여러 파일을 동시에 수정하므로, 문제가 발생했을 때 쉽게 되돌릴 수 있어야 합니다.
# 기존 의존성 제거
npm uninstall tailwindcss postcss autoprefixer
# v4 패키지 설치 (Vite 사용 시)
npm install tailwindcss @tailwindcss/vite
# 또는 PostCSS 사용 시
npm install tailwindcss @tailwindcss/postcssVite 프로젝트:
import tailwindcss from "@tailwindcss/vite";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [tailwindcss()],
});PostCSS 프로젝트:
export default {
plugins: {
"@tailwindcss/postcss": {},
// autoprefixer 제거 — v4가 자동 처리
},
};Next.js 프로젝트:
const config = {
plugins: {
"@tailwindcss/postcss": {},
},
};
export default config;@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
body {
@apply bg-white text-gray-900;
}
}@import "tailwindcss";
@layer base {
body {
background-color: var(--color-white);
color: var(--color-gray-900);
}
}JavaScript 설정 파일의 각 섹션을 CSS @theme으로 변환합니다.
module.exports = {
darkMode: 'class',
theme: {
extend: {
colors: {
primary: '#3b82f6',
secondary: '#64748b',
},
fontFamily: {
sans: ['Pretendard', 'system-ui', 'sans-serif'],
mono: ['JetBrains Mono', 'monospace'],
},
spacing: {
'18': '4.5rem',
},
borderRadius: {
'4xl': '2rem',
},
animation: {
'fade-in': 'fade-in 0.3s ease-out',
},
keyframes: {
'fade-in': {
from: { opacity: '0' },
to: { opacity: '1' },
},
},
},
},
plugins: [
require('@tailwindcss/typography'),
require('@tailwindcss/forms'),
],
}@import "tailwindcss";
@plugin "@tailwindcss/typography";
@plugin "@tailwindcss/forms";
@custom-variant dark (&:where(.dark, .dark *));
@theme {
--color-primary: #3b82f6;
--color-secondary: #64748b;
--font-sans: "Pretendard", system-ui, sans-serif;
--font-mono: "JetBrains Mono", monospace;
--spacing-18: 4.5rem;
--radius-4xl: 2rem;
--animate-fade-in: fade-in 0.3s ease-out;
}
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}v4는 콘텐츠를 자동 감지하므로, content 배열이 필요 없습니다. 단, 특수한 경로(예: node_modules 내 컴포넌트)는 @source로 명시합니다.
@import "tailwindcss";
@source "../node_modules/@shadcn/ui/components";이름이 변경된 유틸리티를 업데이트합니다.
| v3 | v4 | 검색/치환 패턴 |
|---|---|---|
shadow-sm | shadow-xs | 전체 검색 필요 |
shadow (기본) | shadow-sm | 컨텍스트 확인 필요 |
rounded (기본) | rounded-sm | 컨텍스트 확인 필요 |
blur (기본) | blur-sm | 컨텍스트 확인 필요 |
ring (기본) | ring-3 | 컨텍스트 확인 필요 |
ring-offset-* | ring-offset-* (구문 변경) | 확인 필요 |
decoration-clone | box-decoration-clone | 단순 치환 |
decoration-slice | box-decoration-slice | 단순 치환 |
그림자, 둥근 모서리, 블러의 기본 크기 스케일이 재조정되었습니다. v3에서 shadow(기본)가 v4에서는 shadow-sm이 되었으므로, v3에서 shadow-sm을 사용했다면 v4에서 shadow-xs로 변경해야 합니다. 자동 마이그레이션 도구가 이를 처리하지만, 수동으로 마이그레이션하는 경우 주의가 필요합니다.
@apply는 v4에서도 지원되지만, 가능하면 네이티브 CSS로 전환하는 것이 권장됩니다.
/* v3: @apply 사용 */
.btn {
@apply inline-flex items-center gap-2 px-4 py-2 rounded-md font-medium transition-colors;
}
/* v4: 네이티브 CSS + 테마 변수 */
@layer components {
.btn {
display: inline-flex;
align-items: center;
gap: var(--spacing-2);
padding: var(--spacing-2) var(--spacing-4);
border-radius: var(--radius-md);
font-weight: 500;
transition: color 0.15s, background-color 0.15s;
}
}tailwind.config.js → CSS @theme으로 전환darkMode: 'class' → @custom-variant dark (...)content 배열 제거 (필요 시 @source 사용)plugins 배열 → @plugin 디렉티브@tailwind 디렉티브 → @import "tailwindcss"@tailwindcss/postcss로 교체autoprefixer 제거@tailwindcss/vite 플러그인 추가@apply 사용 부분 검토 — 네이티브 CSS 전환 권장ring 유틸리티 변경 확인 — ring-3 등 명시적 크기 필요focus-visible 스타일 재확인Error: It looks like you're trying to use Tailwind CSS with PostCSS
but you haven't configured it correctly.
해결: postcss.config.js에서 기존 tailwindcss 플러그인을 @tailwindcss/postcss로 교체합니다.
v4의 자동 감지가 특정 파일을 놓칠 수 있습니다.
@import "tailwindcss";
@source "../components/**/*.tsx";
@source "../node_modules/@my-ui/**/*.js";OKLCH로의 전환으로 인해 기본 색상 팔레트의 실제 색상값이 미세하게 달라졌습니다.
@theme {
/* OKLCH 대신 기존 hex 값 사용 가능 */
--color-blue-500: #3b82f6;
}v4에서 @apply가 특정 컨텍스트에서 동작하지 않을 수 있습니다.
/* 문제: @apply가 @layer 밖에서 사용됨 */
.my-class {
@apply flex items-center; /* 에러 가능 */
}
/* 해결: @layer 안에서 사용 */
@layer components {
.my-class {
@apply flex items-center; /* OK */
}
}
/* 더 나은 해결: 네이티브 CSS */
@layer components {
.my-class {
display: flex;
align-items: center;
}
}완전한 CSS 전환이 어려운 경우, v4에서도 tailwind.config.js를 @config 디렉티브로 사용할 수 있습니다.
@import "tailwindcss";
@config "../tailwind.config.js";@config는 점진적 마이그레이션을 위한 도구입니다. 최종적으로는 모든 설정을 CSS로 이전하는 것이 목표이지만, 한 번에 전환하기 어려운 대규모 프로젝트에서는 @config를 활용한 단계적 전환이 실용적입니다.
대규모 프로젝트에서는 한 번에 모든 것을 전환하기보다, 단계적으로 접근하는 것이 안전합니다.
@import "tailwindcss" 전환@config로 기존 설정 연결 (임시)tailwind.config.js의 테마를 @theme으로 이전@plugin으로 이전darkMode 설정을 @custom-variant로 이전@config 제거tailwind.config.js 삭제@apply를 네이티브 CSS로 전환이 시리즈를 통해 Tailwind CSS v4의 핵심을 체계적으로 학습했습니다.
@theme 디렉티브와 CSS-first 설정Tailwind CSS v4는 CSS의 본질에 더 가까이 다가간 프레임워크입니다. JavaScript 설정의 복잡성을 CSS의 선언적 구문으로 대체하고, 모던 CSS 기능(레이어, 컨테이너 쿼리, OKLCH, @starting-style)을 유틸리티 클래스의 간결함으로 사용할 수 있게 합니다. 이 시리즈에서 다룬 기법들을 실제 프로젝트에 적용하며, 더 빠르고 유연한 스타일링 경험을 만들어가시길 바랍니다.
이 글이 도움이 되셨나요?
관련 주제 더 보기
Tailwind CSS v4로 프로덕션 디자인 시스템을 구축합니다. 토큰 계층 설계, 컴포넌트 라이브러리, 테마 시스템, 접근성, 팀 협업 전략을 실전 중심으로 다룹니다.
Tailwind CSS v4의 @custom-variant, @plugin 디렉티브, CSS 기반 확장 시스템, 그리고 기존 JS 플러그인에서의 마이그레이션을 실전 중심으로 다룹니다.
Tailwind CSS v4의 다크 모드 전략, CSS 커스텀 프로퍼티 기반 런타임 테마 전환, 다중 테마 패턴, 그리고 next-themes와의 통합을 실전 중심으로 다룹니다.