오늘은 버전 업그레이드가 된 TailwindCSS v4 사용법에 대해 이야기 해보려고 한다.
보통 나는 프론트엔드 개발을 할 때 Next.js + TailwindCSS를 사용한다. 이번에 우연히 새로운 프로젝트를 셋팅하게 됐는데, 이전처럼 셋팅하니 에러가 난다?
⨯ ./app/globals.css
Error evaluating Node.js code
Error: It looks like you're trying to use `tailwindcss` directly as a PostCSS plugin. The PostCSS plugin has moved to a separate package, so to continue using Tailwind CSS with PostCSS you'll need to install `@tailwindcss/postcss` and update your PostCSS configuration.
[at We (/Users/jeongjin-ug/jinuk_project/clone_coding/drive-sys/node_modules/tailwindcss/dist/lib.js:35:2121)]
[at eval (turbopack:///[project]/postcss.config.mjs/transform.ts:66:14)]
[at <anonymous>]
[at Module.init (turbopack:///[project]/postcss.config.mjs/transform.ts:53:33)]
[at run (turbopack:///[turbopack-node]/ipc/evaluate.ts:77:20)]
근데 좀 이상했다. v3까지는 당연히 따라오던 tailwind.config 파일과 postcss.config 파일이 제대로 작동하지 않았고, 심지어 공식 문서에서는 “설정 없이도 시작 가능”이라는 메시지가 보였다.

그래서 Reddit이나 Stack Overflow, 공식 문서 등등 찾아보다가 ‘v4가 v3랑 셋팅법이 좀 달라졌구나~’라고 생각이 들어서 뭐가 다른지 블로그를 남기게 되었다.
(v3셋팅대로 하면 에러나고, 에러를 고쳐서 커스텀 색상 클래스가 안 먹더라 하…)
기존 v3의 Tailwind 셋팅 방식
TailwindCSS v3는 설정 중심의 구조였다. 거의 모든 설정은 tailwind.config와 postcss.config에 모여있었다.
tailwind.config.ts 예시:
import type { Config } from "tailwindcss";
const config: Config = {
content: ["./src/**/*.{ts,tsx}"],
theme: {
extend: {
colors: {
primary: "#FF5570",
},
},
},
plugins: [],
};
export default config;
global.css 예시:
@tailwind base;
@tailwind components;
@tailwind utilities;
---
그리고 여기에 autoprefixer나 postcss-import 등은 별도 설치가 필요했었다.
postcss.config.mjs 예시:
export default {
plugins: {
'postcss-import': {}, // CSS 파일 간 import 지원
'tailwindcss': {}, // Tailwind CSS 적용
'autoprefixer': {}, // 브라우저 벤더 프리픽스 자동 추가
},
};
Tailwind v4의 새로운 설정 흐름
v4는 설정 철학이 좀 다르다. 핵심은 두 가지다.
“CSS-first 구성”
- CSS 파일 내에서 @config, @theme inline을 통해 설정 가능
“PostCSS 자동화”
- 별도 autoprefixer, postcss-import 없이 @tailwindcss/postcss만 사용
항목 | v3 | v4 |
설정 중심 | tailwind.config.ts | CSS 파일 (globals.css) |
import 방식 | @tailwind 3종 | @import "tailwindcss" 한 줄 |
설정 전달 방식 | PostCSS + JS 객체 | @config, @theme inline |
자동 처리 | X | prefix, import 자동 내장 |
완성한 Tailwind CSS v4 설정 코드
tailwind.config.ts (선택 옵션)
import type { Config } from 'tailwindcss';
import "tailwindcss-animated";
const config: Config = {
content: [ // which files to search for tailwind classes
'./app/**/*.{js,ts,jsx,tsx}', /* → Find tailwind classes used as class ='' in files defined here and convert them to CSS */
'./components/**/*.{js,ts,jsx,tsx}',
],
theme: {
extend: { // setting to extend the default tailwind theme
colors: {
brand: { // set brand color
DEFAULT: "#FA7275", /* → Register custom color: Use like bg-brand, text-red, bg-light-200 */
100: "#EA6365",
},
red: "#FF7474",
error: "#B80000",
green: "#3DD9B3",
orange: "#F9AB72",
blue: "#56BBFF",
pink: "#EEA8FD",
light: {
100: "#333F4E",
200: "#A3B2C7",
300: "#F2F5F9",
400: "#F2F4F8",
},
dark: {
100: "#04050C",
200: "#131524"
}
},
fontFamily: { // set font family
poppins : [ /* → Resister a custom font (ususally a variable declared as @font-face or Google Fonts) with a class name*/
"var(--font-poppins)"
]
},
boxShadow: { // custome shadow setting:
"drop-1": "0px 10px 30px 0px rgba(66, 71, 97, 0.1)", // drop-1: default shadow
"drop-2": "0px 8px 30px 0 rgba(65, 89, 214, 0.3)", // drop-2: accent shadow
"drop-3": "0px 8px 30px 0 rgba(65, 89, 214, 0.1)", // drop-3: accent shadow
},
borderRadius: { // set border radius
lg: "var(--radius)", /* → tailwind default rounded-lg classes are mapped to values set here */
md: "calc(var(--radius) - 2px)",
sm: "calc(var(--radius) - 4px)",
},
keyframes: { // custom animation setting:
"caret-blink": { /* → custom animation available with tailwind utility animate-caret-blink */
"0%, 70%, 100%" : { opacity: "1" },
"20%, 50%" : { opacity: "0" }
}
},
animation: {
"caret-blink": "caret-blink 1.25s ease-out infinite",
},
},
},
plugins: [ // external tailwind plugins
require("tailwindcss-animate"), // tailwindcss-animated: animation plugin
]
};
export default config;
app/globals.css
@import "tailwindcss";
@config "../tailwind.config.ts";
:root {
--background: #ffffff;
--foreground: #171717;
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
}
@media (prefers-color-scheme: dark) {
:root {
--background: #0a0a0a;
--foreground: #ededed;
}
}
body {
background: var(--background);
color: var(--foreground);
}
postcss.config.mjs
export default {
plugins: {
"@tailwindcss/postcss": {}, // 이거 하나면 끝
},
};
만약, tailwind.config.ts를 사용하기 싫다면?
→ Tailwind CSS v4에서는 기존 tailwind.config.ts에 작성하던 설정 코드를 globals.css에 직접 작성하면 된다. 이제 설정은 config가 아니라 globals.css에다 쓴다 — @config, @theme inline, CSS 변수로.
https://www.reddit.com/r/tailwindcss/comments/1i9e7k2/solution_tailwind_v4_missing_tailwindconfigjs/
From the tailwindcss community on Reddit: (Solution) Tailwind V4 Missing tailwind.config.js
Explore this post and more from the tailwindcss community
www.reddit.com
이건 내가 봤던 Reddit 글이다. 참고하면 좋을듯?
(Reddit이 참 노다지야 노다지)
Vite 프로젝트라면, PostCSS 플러그인을 굳이 설정하지 않아도 @tailwindcss/vite 플러그인 하나만 사용해도 모든 설정이 가능하다고 한다!
참고: https://tailwindcss.com/docs/upgrade-guide#using-vite
Upgrade guide - Getting started
Upgrading your Tailwind CSS projects from v3 to v4.
tailwindcss.com
끝내는 말
v4로 변한 걸 모르고 있다가, 셋팅 할 때 에러가 나서 좀 당황했다.. 그런데 뭐 알고보니까 디자인 시스템 연결성을 조금 더높여준 업그레이드인 거 같다는 생각이 들었다. 설정 파일을 줄이면서 선택옵션으로는 사용할 수 있는 구조가 마음에 들었다.
v3에서 v4로 옮겨가면서 느낀 핵심!
- 설정 파일이 더는 필수가 아니라는 점
- CSS 파일 하나로 색상, 폰트, 다크 모드까지 커버 가능하다는 점
- 협업 효율?이 올라가고, 파일은 줄어든다는 점
결론은 ‘v4 좋은 거 같다!’
'Frontend Dev Log' 카테고리의 다른 글
disabled 옵션은 왜 필요할까? (0) | 2025.05.26 |
---|---|
C언어 배열이랑 JavaScript 배열이 다르다고? (0) | 2025.05.06 |
디자인 시스템, 프론트엔드 개발자는 어디까지 알아야 할까? (0) | 2025.05.05 |