Devlery
Blog/Tailwind CSS

Tailwind CSS v4 실전 가이드: CSS 우선 설정과 새로운 기능 총정리

Tailwind CSS v4의 CSS-first 설정 패러다임, Oxide 엔진의 빌드 성능 개선, Container Queries 등 새 기능, 그리고 v3에서의 마이그레이션 방법을 실전 코드와 함께 정리합니다.

프론트엔드 프로젝트를 시작할 때 tailwind.config.js, postcss.config.js, postcss-import, autoprefixer... 설정 파일 하나를 만들기 위해 또 다른 설정 파일이 필요했던 경험, 한 번쯤 있지 않을까요? Tailwind CSS는 utility-first라는 혁신적인 접근으로 CSS 작성 방식을 바꿔놓았지만, 정작 프레임워크를 설정하는 과정은 JavaScript 생태계의 "설정 피로(config fatigue)"에서 자유롭지 못했습니다.

Tailwind CSS v4는 이 문제를 정면으로 해결합니다. JavaScript 설정 파일 중심에서 CSS 우선 설정 으로 패러다임이 전환되었고, Rust 기반 Oxide 엔진으로 빌드 성능이 극적으로 개선되었습니다. 2025년 1월 정식 출시 이후 v4.1, v4.2를 거치며 안정성과 기능 모두 성숙한 단계에 접어들었습니다. 지금이 v4를 살펴볼 적기입니다.

무엇이 달라졌나 — 핵심 변화 3가지

v4의 변화를 한마디로 요약하면 "CSS로 돌아가기"입니다. 설정도 CSS, 디자인 토큰도 CSS 변수, 빌드 엔진도 CSS 네이티브 도구로 교체되었습니다. 핵심 변화 세 가지를 살펴보겠습니다.

⚙️v3 — JavaScript 설정
tailwind.config.js
postcss.config.mjs
postcss-import
autoprefixer
PostCSS 엔진
CSS 출력

📄 설정 파일 3개 + 패키지 3개

v4 — CSS 우선 설정
@import "tailwindcss"
globals.css — 한 줄로 시작
Oxide 엔진 (Rust)
Lightning CSS 내장
CSS 출력

설정 파일 1개 + 패키지 1개

1. CSS 우선 설정 — tailwind.config.js 없이 시작하기

v4에서 가장 큰 변화는 tailwind.config.js가 더 이상 필요하지 않다는 점입니다. 테마 커스터마이징, 컬러 팔레트, 폰트, 브레이크포인트 — 이 모든 설정을 CSS 안에서 @theme 디렉티브로 정의합니다.

프로젝트를 시작하는 데 필요한 CSS는 단 한 줄입니다.

@import "tailwindcss";

커스텀 테마가 필요하다면 같은 CSS 파일에 @theme 블록을 추가하면 됩니다.

@import "tailwindcss";

@theme {
  --font-display: "Satoshi", "sans-serif";
  --breakpoint-3xl: 1920px;
  --color-brand-100: oklch(0.93 0.03 220);
  --color-brand-500: oklch(0.68 0.16 230);
  --color-brand-900: oklch(0.30 0.08 230);
  --ease-fluid: cubic-bezier(0.3, 0, 0, 1);
}

@theme 에 정의된 값들은 자동으로 CSS 변수로 노출됩니다. 즉, JavaScript에서 getComputedStyle로 직접 접근할 수 있습니다.

// v3에서는 resolveConfig()가 필요했지만, v4에서는 CSS 변수를 직접 사용합니다
const brandColor = getComputedStyle(document.documentElement)
  .getPropertyValue('--color-brand-500')

// React 컴포넌트에서 동적 스타일링에 활용
function ThemedButton({ children }: { children: React.ReactNode }) {
  return (
    <button
      style={{ backgroundColor: 'var(--color-brand-500)' }}
      className="text-white px-4 py-2 rounded-sm"
    >
      {children}
    </button>
  )
}

이 방식은 다크 모드나 테마 전환에서 특히 유용합니다. CSS 변수를 런타임에 바꾸면 JavaScript 번들 재빌드 없이 테마가 즉시 반영되기 때문입니다.

2. Oxide 엔진 — Rust가 가져온 빌드 성능 혁신

v4의 내부 엔진은 Rust로 완전히 재작성된 Oxide 엔진입니다. PostCSS에 의존하던 기존 파이프라인을 걷어내고, Lightning CSS를 통합해 파싱, 변환, 벤더 프리픽싱, 축소를 단일 도구로 처리합니다.

별도로 postcss-importautoprefixer를 설치할 필요가 없습니다. @import 처리, 벤더 프리픽싱, CSS 네스팅까지 모두 엔진에 내장되어 있습니다.

3. 콘텐츠 자동 감지

v3에서는 content 배열에 어떤 파일을 스캔할지 일일이 지정해야 했습니다. v4에서는 이 과정이 자동화되었습니다. 프로젝트 내 HTML, JSX, TSX 파일을 자동으로 감지하고, 필요하면 @source 디렉티브로 세밀하게 제어할 수 있습니다.

@import "tailwindcss";

/* 특정 경로 제외 */
@source not "./src/components/legacy";

/* 특정 유틸리티 강제 포함 (v3의 safelist 대체) */
@source inline("underline");

v3 vs v4 — 설정 비교

말로 설명하는 것보다 코드로 비교하는 것이 더 직관적입니다. 같은 프로젝트를 v3와 v4로 각각 설정하면 어떻게 달라지는지 살펴보겠습니다.

v3 설정 — 여러 파일에 분산된 설정

// tailwind.config.js
module.exports = {
  content: ['./src/**/*.{js,ts,jsx,tsx}'],
  theme: {
    extend: {
      colors: {
        brand: {
          100: '#e0f2fe',
          500: '#0ea5e9',
          900: '#0c4a6e',
        },
      },
      fontFamily: {
        display: ['Satoshi', 'sans-serif'],
      },
      screens: {
        '3xl': '1920px',
      },
    },
  },
  plugins: [],
}
// postcss.config.mjs
export default {
  plugins: {
    "postcss-import": {},
    tailwindcss: {},
    autoprefixer: {},
  },
}
/* globals.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

v4 설정 — CSS 한 파일로 통합

/* globals.css */
@import "tailwindcss";

@theme {
  --font-display: "Satoshi", "sans-serif";
  --breakpoint-3xl: 1920px;
  --color-brand-100: oklch(0.93 0.03 220);
  --color-brand-500: oklch(0.68 0.16 230);
  --color-brand-900: oklch(0.30 0.08 230);
}
// postcss.config.mjs (PostCSS 사용 시)
export default {
  plugins: {
    "@tailwindcss/postcss": {},
  },
}

v3에서 3개 파일 + 3개 npm 패키지가 필요했던 설정이, v4에서는 CSS 파일 하나와 단일 PostCSS 플러그인으로 줄어듭니다. Vite를 사용한다면 PostCSS 설정조차 필요 없습니다.

// vite.config.ts — PostCSS 설정 파일이 아예 필요 없음
import { defineConfig } from "vite"
import tailwindcss from "@tailwindcss/vite"

export default defineConfig({
  plugins: [tailwindcss()],
})

빌드 성능은 얼마나 빨라졌나

빌드 성능 벤치마크 — Catalyst 템플릿 기준
v3.4v4.0
전체 빌드3.78x 빠름
v3
378ms
v4
100ms
증분 빌드 (새 CSS 포함)8.45x 빠름
v3
44.8ms
v4
5.3ms
증분 빌드 (새 CSS 없음)182x 빠름 🚀
v3
35ms
v4
0.192ms

Oxide 엔진의 성능 개선은 수치로 확인할 수 있습니다. Tailwind Labs가 공개한 Catalyst 템플릿 기준 벤치마크입니다.

측정 항목v3.4v4.0개선 비율
전체 빌드378ms100ms3.78x
증분 빌드 (새 CSS 포함)44ms5ms8.8x
증분 빌드 (새 CSS 없음)35ms192μs182x

특히 증분 빌드에서의 개선이 눈에 띕니다. 새로운 CSS가 필요 없는 파일 변경 시 182배 빠른 응답 속도는, 대규모 프로젝트에서 HMR 체감 속도를 근본적으로 바꿔놓습니다. 커뮤니티에서도 v3 기준 8~15초 걸리던 빌드가 v4에서 1초 미만으로 줄었다는 보고가 이어지고 있습니다.

새로운 기능 심층 탐구

v4에서 추가된 기능들은 단순한 유틸리티 확장이 아니라, 모던 CSS 스펙을 프레임워크 수준에서 적극 수용한 결과입니다.

Container Queries — 컴포넌트 단위 반응형 디자인

v3에서 별도 플러그인(@tailwindcss/container-queries)이 필요했던 Container Queries가 v4에서는 기본 내장되었습니다. 뷰포트가 아닌 부모 컨테이너의 크기에 따라 반응하는 디자인을 만들 수 있습니다.

<!-- 컨테이너 선언 -->
<div class="@container">
  <div class="grid grid-cols-1 @sm:grid-cols-3 @lg:grid-cols-4">
    <div class="p-4">카드 1</div>
    <div class="p-4">카드 2</div>
    <div class="p-4">카드 3</div>
  </div>
</div>

<!-- Max-width 쿼리 -->
<div class="@container">
  <div class="grid grid-cols-3 @max-md:grid-cols-1">
    <!-- 컨테이너가 md보다 작으면 1컬럼 -->
  </div>
</div>

<!-- 범위 쿼리 (Min + Max) -->
<div class="@container">
  <div class="flex @min-md:@max-xl:hidden">
    <!-- md~xl 범위에서만 숨김 -->
  </div>
</div>

사이드바에 배치된 위젯, 대시보드 카드 등 같은 컴포넌트가 다양한 크기의 컨테이너에서 사용되는 경우에 특히 유용합니다. 미디어 쿼리 기반의 반응형 디자인이 "페이지 전체"를 기준으로 했다면, Container Queries는 "컴포넌트 자체" 를 기준으로 반응하게 해줍니다.

동적 유틸리티 값

v3에서는 기본 스케일에 없는 값을 사용하려면 tailwind.config.js에 값을 추가하거나 대괄호 구문([])을 써야 했습니다. v4에서는 임의의 숫자 값을 그대로 사용할 수 있습니다.

<!-- v3: tailwind.config.js에 정의하거나 [값]으로 사용 -->
<!-- v4: 설정 없이 바로 사용 가능 -->
<div class="grid grid-cols-15"><!-- 15컬럼 그리드 --></div>
<div class="mt-17"><!-- 17단위 마진 --></div>
<div class="w-29"><!-- 29단위 너비 --></div>

내부적으로는 spacing 스케일이 CSS 변수 기반의 동적 계산으로 바뀌었습니다.

/* v4가 생성하는 CSS */
.mt-8 { margin-top: calc(var(--spacing) * 8); }
.w-17 { width: calc(var(--spacing) * 17); }

확장된 Gradient API

그래디언트도 더 세밀하게 제어할 수 있습니다. CSS 표준 명칭에 맞춰 bg-gradient-to-*bg-linear-to-*로 변경되었고, 각도 지정, 색상 보간 방식 선택, 원뿔형/방사형 그래디언트까지 지원합니다.

<!-- 각도 지정 그래디언트 -->
<div class="bg-linear-45 from-indigo-500 via-purple-500 to-pink-500"></div>

<!-- OKLCH 색상 공간으로 보간 -->
<div class="bg-linear-to-r/oklch from-indigo-500 to-teal-400"></div>

<!-- 원뿔형 그래디언트 -->
<div class="size-24 rounded-full bg-conic/[in_hsl_longer_hue] from-red-600 to-red-600"></div>

<!-- 방사형 그래디언트 -->
<div class="size-24 rounded-full bg-radial-[at_25%_25%] from-white to-zinc-900 to-75%"></div>

새로운 Variants

v4에서 추가된 variant들은 기존에 커스텀 CSS나 JavaScript가 필요했던 상호작용 패턴을 유틸리티 클래스만으로 해결합니다.

<!-- not-* variant: 특정 상태가 아닐 때 스타일 적용 -->
<button class="opacity-100 not-hover:opacity-75">
  호버하지 않으면 반투명
</button>

<!-- @starting-style: JavaScript 없이 진입 애니메이션 -->
<div popover id="menu" class="transition-discrete starting:open:opacity-0 open:opacity-100">
  팝오버가 열릴 때 페이드인
</div>

<!-- inert: 비활성 요소 스타일링 -->
<div class="inert:opacity-50 inert:pointer-events-none">
  비활성 상태 영역
</div>

not-*은 조건부 스타일링을, starting:은 CSS-only 진입 애니메이션을 가능하게 하며, in-*group 클래스 없이도 부모 상태를 참조할 수 있게 해줍니다.

v4.1~v4.2 — 계속되는 진화

정식 출시 이후에도 Tailwind v4는 빠르게 기능을 확장하고 있습니다.

v4.1: Text Shadow, Mask, 폼 검증 Variants

<!-- Text Shadow 유틸리티 -->
<h1 class="text-shadow-lg text-shadow-black/30">그림자 텍스트</h1>

<!-- 방향 마스크 -->
<div class="mask-t-from-50% bg-[url(/img/mountains.jpg)]"></div>

<!-- 폼 검증 (사용자 상호작용 후에만 표시) -->
<input
  required
  class="border user-valid:border-green-500 user-invalid:border-red-500"
  placeholder="이메일 입력"
/>

<!-- 터치/마우스 장치 구분 -->
<div class="grid grid-cols-6 gap-2 pointer-coarse:grid-cols-3 pointer-coarse:gap-4">
  <!-- 터치 디바이스에서 더 큰 터치 타겟 -->
</div>

user-valid/user-invalid variant는 기존 valid/invalid와 달리, 사용자가 실제로 필드와 상호작용한 후에만 검증 스타일을 보여줍니다. 페이지 로드 시 빈 필수 필드가 빨간색으로 표시되는 문제를 해결합니다.

v4.2: 새 컬러 팔레트, Webpack 지원

v4.2에서는 oklch 색상 공간으로 정의된 새로운 컬러 팔레트 4종이 추가되었습니다. mauve (보라빛 회색), olive (올리브 톤), mist (안개빛 블루그레이), taupe (토프/황갈색)로, 기존의 선명한 팔레트와 함께 차분하고 자연스러운 디자인에 활용할 수 있습니다.

Webpack 공식 플러그인(@tailwindcss/webpack)도 이 버전에서 추가되어, Vite와 PostCSS에 이어 주요 번들러가 모두 공식 지원됩니다.

버전주요 기능

🚀 v4.0

  • CSS 우선 설정@theme 디렉티브로 JavaScript 설정 대체
  • Oxide 엔진 — Rust 기반 재작성, Lightning CSS 통합
  • Container Queries@container 기본 내장
  • 동적 유틸리티 값grid-cols-15, mt-17 등 임의 값 사용
  • 새 Variantsnot-*, starting:, inert:, in-*
  • 3D Transformrotate-x-*, perspective-*

✨ v4.1

  • Text Shadowtext-shadow-* 유틸리티 추가
  • Mask 유틸리티mask-t-from-*, mask-b-from-*
  • 폼 검증 Variantsuser-valid:, user-invalid:
  • 포인터 장치 Variantspointer-coarse:, pointer-fine:
  • Safe Alignmentitems-safe-center

🆕 v4.2

  • 새 컬러 팔레트 — mauve, olive, mist, taupe (OKLCH 기반 4종)
  • Webpack 공식 플러그인@tailwindcss/webpack 추가
  • Logical Properties — 국제화(RTL) 지원 강화
  • Font Featuresfont-variant-numeric 등 타이포그래피 세밀 제어

마이그레이션 가이드 — v3에서 v4로

자동 마이그레이션 도구

Tailwind Labs는 공식 마이그레이션 도구를 제공합니다. 약 90%의 기계적 변경을 자동으로 처리해줍니다.

npx @tailwindcss/upgrade

Node.js 20 이상이 필요하며, HTML, JSX, TSX, CSS 파일을 자동으로 스캔하여 클래스 이름을 리네임합니다. 대부분의 프로젝트에서 1~2시간 내에 마이그레이션을 완료할 수 있다고 알려져 있습니다.

주요 유틸리티 리네임

자동 도구가 처리해주지만, 어떤 것들이 바뀌었는지 알아두면 코드 리뷰 시 유용합니다.

v3v4비고
shadow-smshadow-xs한 단계씩 아래로 이동
shadowshadow-sm
rounded-smrounded-xs
roundedrounded-sm
outline-noneoutline-hidden의미 명확화
ringring-3기본 너비 제거
bg-gradient-to-*bg-linear-to-*CSS 표준 명칭

동작 변경 — 수동 확인이 필요한 부분

자동 도구로 처리되지 않는 동작 변경 사항들이 있습니다. 이 부분은 마이그레이션 후 수동으로 확인해야 합니다.

<!-- 1. 기본 border 색상 변경: gray-200 → currentColor -->
<!-- v3 -->
<div class="border"></div>
<!-- v4: 명시적으로 색상 지정 필요 -->
<div class="border border-gray-200"></div>

<!-- 2. Important 수정자 위치 변경 -->
<!-- v3 -->
<div class="!flex !bg-red-500"></div>
<!-- v4 -->
<div class="flex! bg-red-500!"></div>

<!-- 3. Variant 스태킹 순서: 우→좌에서 좌→우로 -->
<!-- v3 -->
<ul class="first:*:pt-0"></ul>
<!-- v4 -->
<ul class="*:first:pt-0"></ul>

커스텀 CSS를 작성하고 있었다면 다음 변경도 확인해야 합니다.

/* theme() 함수 → CSS 변수 */
/* v3 */
.my-class {
  background-color: theme(colors.red.500);
}
/* v4 */
.my-class {
  background-color: var(--color-red-500);
}

/* 커스텀 유틸리티 정의 방식 */
/* v3 */
@layer utilities {
  .tab-4 { tab-size: 4; }
}
/* v4 */
@utility tab-4 {
  tab-size: 4;
}

기존 설정 파일 호환

당장 tailwind.config.js를 삭제하지 않아도 됩니다. @config 디렉티브로 기존 설정을 참조할 수 있습니다.

@import "tailwindcss";
@config "../../tailwind.config.js";

단, corePlugins, safelist, separator 옵션은 v4에서 지원되지 않으므로 해당 기능을 사용 중이었다면 대체 방법을 찾아야 합니다. safelist는 앞서 소개한 @source inline() 디렉티브로 대체할 수 있습니다.

브라우저 지원 범위

v4는 @property, color-mix() 등 모던 CSS 기능에 의존하므로 지원 브라우저 범위가 v3보다 좁아졌습니다.

브라우저최소 버전
Chrome111+
Safari16.4+
Firefox128+

IE나 구형 Safari를 지원해야 하는 프로젝트라면 v3.4를 유지하는 것이 현실적입니다.

프레임워크별 설정

Next.js

Next.js는 PostCSS 기반으로 통합합니다.

npm install tailwindcss @tailwindcss/postcss postcss
// postcss.config.mjs
const config = {
  plugins: {
    "@tailwindcss/postcss": {},
  },
}
export default config
/* app/globals.css */
@import "tailwindcss";

Vite (React, SvelteKit 등)

Vite 기반 프로젝트에서는 전용 플러그인을 사용하는 것이 권장됩니다. PostCSS 설정 파일이 아예 필요 없습니다.

npm install tailwindcss @tailwindcss/vite
// vite.config.ts
import { defineConfig } from "vite"
import tailwindcss from "@tailwindcss/vite"

export default defineConfig({
  plugins: [tailwindcss()],
})

Webpack (v4.2+)

CRA(Create React App)나 기존 Webpack 프로젝트에서도 공식 플러그인으로 지원됩니다.

npm install tailwindcss @tailwindcss/webpack
// webpack.config.js
const tailwindcss = require('@tailwindcss/webpack')

module.exports = {
  plugins: [tailwindcss()],
}

생태계 호환성

v4 전환을 망설이게 만드는 가장 큰 요인은 생태계 호환성일 것입니다. 다행히 주요 라이브러리들은 이미 v4를 완전 지원합니다.

shadcn/ui 는 모든 컴포넌트가 Tailwind v4 + React 19에 맞게 업데이트되었습니다. CLI가 v4 기반으로 프로젝트를 초기화하며, HSL 색상이 OKLCH로 변환됩니다. 다만, tailwindcss-animate가 deprecated 되었으므로 tw-animate-css로 교체해야 합니다.

Headless UI 는 Tailwind Labs에서 직접 관리하는 라이브러리이므로 v4 완전 호환이고, Radix UI 는 CSS 유틸리티와 독립적으로 동작하므로 별도 이슈가 없습니다.

프레임워크통합 방식상태
Next.js@tailwindcss/postcss완전 지원
Vite@tailwindcss/vite완전 지원 (권장)
Astro 5.2+@tailwindcss/vite네이티브 지원
Webpack@tailwindcss/webpack공식 지원 (v4.2+)
Nuxt@tailwindcss/postcss지원
SvelteKit@tailwindcss/vite지원

마무리 — 언제 전환해야 할까

Tailwind CSS v4는 설정 방식, 빌드 성능, CSS 기능 활용 세 측면 모두에서 의미 있는 진전을 이뤘습니다. CSS 우선 설정은 "JavaScript 설정 파일이 너무 많다"는 비판에 대한 실질적인 답변이고, Oxide 엔진의 성능 개선은 대규모 프로젝트에서 체감할 수 있는 수준입니다.

새 프로젝트를 시작한다면 v4를 선택하지 않을 이유가 없습니다. 설정이 간소하고, 성능이 좋고, 모던 CSS 기능을 즉시 활용할 수 있습니다.

기존 v3 프로젝트를 마이그레이션할 때는 몇 가지를 확인해야 합니다. 브라우저 지원 범위가 요구사항에 맞는지, 사용 중인 서드파티 플러그인이 v4를 지원하는지, shadcn/ui 등의 의존 라이브러리가 업데이트되었는지 점검하세요. 조건이 맞는다면 자동 마이그레이션 도구가 대부분의 작업을 처리해줍니다.

구형 브라우저를 지원해야 하거나 v3 전용 플러그인에 크게 의존하고 있다면, 서두를 필요 없이 v3.4를 유지하면서 생태계 성숙을 기다리는 것도 합리적인 판단입니다. 중요한 것은 프로젝트의 실제 요구사항에 맞는 선택을 하는 것이니까요.