build tooling · cli / vite / postcss / lightning css

[check: …]
📖 Pair this live concept demo with the companion guide (.md) — this page is the rendered ground truth. ↗ Builds on tailwind: @source & content detection (these build tools are what actually perform the source scan at compile time) and frontend/tailwind: customization (the @theme tokens the pipeline emits).

v4 has exactly three build paths — pick one

Every v4 project compiles @import "tailwindcss" into a static, tree-shaken CSS file through one of three entry points. They all use the same engine (Lightning CSS, internally) and produce the same output — the only difference is how the compiler is wired into your build pipeline. There is no more tailwind.config.js at the root by default; configuration lives in CSS via @theme, @source, @utility, @plugin.

pathpackagewire it intobest for
CLI @tailwindcss/cli a shell command / npm script static sites, no-bundler setups, CI; also ships a standalone binary (no Node)
Vite plugin @tailwindcss/vite vite.config.tsplugins: [tailwindcss()] Vite apps (SvelteKit, Laravel, React Router, Nuxt, SolidJS) — fastest HMR
PostCSS plugin @tailwindcss/postcss postcss.config.mjs"@tailwindcss/postcss": {} frameworks already running PostCSS (Next.js, Angular, Rails, Symfony)
Play CDN (this page) @tailwindcss/browser a single <script> tag prototyping / demos — compiles in the browser, not for production

All four feed the same CSS entry point. The first three ship a static dist.css; the Play CDN compiles at runtime from the live DOM.

the entry point — ONE line, then optional directives

In v4 the stylesheet is the configuration. There is no JS config file to point at — the compiler reads your CSS top-to-bottom and treats every at-rule (@theme, @source, @utility, @custom-variant, @plugin) as an instruction. A real-world entry file looks like this:

/* app.css — the ONLY file the build tool reads */ @import "tailwindcss"; @theme { --color-brand: oklch(0.7 0.15 250); --breakpoint-3xl: 120rem; } @source "../src/**/*.{tsx,jsx,html}"; @source "../node_modules/@acme/ui"; @source not "../legacy"; @custom-variant pointer-coarse (@media (pointer: coarse)); @utility tab-4 { tab-size: 4; }

Migrating a v3 codebase? @config "../tailwind.config.js" bridges a legacy JS config into v4 — but it's an escape hatch, not the destination.

1 · choose a build path → see the recommended setup

Click a path. The snippet below swaps to the exact install + config you need. Every path ends with the same app.css from the panel above — the difference is purely how the compiler is hooked in.

2 · Lightning CSS — the engine inside all three

v4 replaced PostCSS + autoprefixer + cssnano with Lightning CSS (a Rust-based CSS transformer). It runs inside the CLI, the Vite plugin, and the PostCSS plugin — you don't configure it directly, but it is why v4 builds are faster and the output is smaller. It handles four jobs the old stack split across three tools:

jobv3 (old stack)v4 (Lightning CSS)
minification cssnano built-in — smarter shorthand merging, ~20-40% smaller on real apps
vendor prefixes autoprefixer built-in — adds only the prefixes your browserslist needs
nesting polyfill postcss-nesting built-in — compiles @nest / native nesting for older targets
@import inlining postcss-import built-in — @import "tailwindcss" is resolved & inlined

Representative minified+gzipped output sizes (a typical marketing page, ~200 utility classes). Your mileage depends on how many utilities you actually use — v4 only ships what @source detected.

buildraw CSSminifiedgzippedvs v3
v3 (postcss + cssnano + autoprefixer)~48 KB~14 KB~4.1 KBbaseline
v4 (Lightning CSS, --minify)~46 KB~10 KB~3.2 KB~22% smaller gz

3 · proof: this page's utilities compiled (the CDN works)

The card below is styled purely with Tailwind utility classes (no inline styles for layout). The gold-check badge in the header asserts getComputedStyle().display === "flex" on it once the CDN finishes compiling. This is the same compilation step the CLI / Vite / PostCSS plugin do at build time — here it happens in the browser via the Play CDN. If the badge turns green, the pipeline works.

display: flex

Compiled from flex items-center gap-4.

utility layer OK

Preflight + theme + utilities all resolved.

display: — · gap: — · border-radius: —

intent → command

intentcommand / configwhy
quick one-off build npx @tailwindcss/cli -i app.css -o dist.css no install, scans cwd, writes one file
watch mode (dev) npx @tailwindcss/cli -i app.css -o dist.css --watch rebuilds on source change; pair with your dev server
production build npx @tailwindcss/cli -i app.css -o dist.css --minify Lightning CSS minify + dead-code removal
Vite app npm i tailwindcss @tailwindcss/vite + plugin in config fastest HMR; zero-config once @import "tailwindcss" is in CSS
Next.js / Angular npm i tailwindcss @tailwindcss/postcss + postcss.config plugs into the framework's existing PostCSS pipeline
target older browsers set browserslist in package.json Lightning CSS polyfills nesting + adds prefixes accordingly
no Node available download the standalone CLI binary from GitHub releases single executable — same flags as the npm CLI
bridge a v3 config @config "../tailwind.config.js"; in app.css escape hatch while migrating; not for greenfield