Project Setup
Structure a Tailwind v4 project, configure source detection, set up editor tooling, and establish a development workflow your whole team shares.
Installation gets Tailwind compiling. This page covers the decisions that make a project pleasant to work in six months later.
Project structure#
Tailwind v4 needs exactly one thing: a CSS file that imports it. Everything else follows your framework's conventions.
my-app/
├── src/
│ ├── styles/
│ │ ├── app.css ← the only file that imports Tailwind
│ │ └── typography.css ← optional: hand-written CSS
│ ├── components/
│ └── main.ts
├── index.html
├── vite.config.ts
└── package.json@import "tailwindcss";
/* Design tokens for this project */
@theme {
--color-brand-500: oklch(0.62 0.19 264);
--font-display: "Satoshi", sans-serif;
}
/* Custom utilities and variants */
@utility scrollbar-hidden {
&::-webkit-scrollbar {
display: none;
}
}
/* Hand-written CSS, imported after Tailwind so tokens are available */
@import "./typography.css";Source detection#
v4 scans your project automatically, so there is no content array to maintain. It:
- Starts from the directory containing your CSS file and walks up to the project root.
- Respects
.gitignore. - Skips binary files,
node_modulesand.git.
You only need @source when Tailwind cannot see a file it should.
Adding sources#
/* A component library shipped as compiled JS in node_modules */
@source "../node_modules/@acme/ui";
/* Templates rendered outside the project root */
@source "../../shared/templates/**/*.blade.php";Excluding sources#
v4.1
@source not "./src/legacy";Safelisting classes#
When class names are built at runtime — bg-${color}-500 — Tailwind cannot see them. Declare them explicitly:
@source inline("underline");
@source inline("{hover:,}bg-red-{50,{100..900..100},950}");The second line generates every bg-red-* shade and its hover: variant.
Editor setup#
IntelliSense#
Install the official Tailwind CSS IntelliSense extension (VS Code) or the JetBrains plugin. It provides completion, hover previews of the generated CSS, and colour swatches.
For class names in variables or helper functions, tell it where to look:
{
"editor.quickSuggestions": { "strings": "on" },
"tailwindCSS.experimental.classRegex": [
["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"],
["cx\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"]
],
"files.associations": { "*.css": "tailwindcss" }
}The last line stops the CSS language server flagging @theme and @utility as unknown at-rules.
Class sorting#
prettier-plugin-tailwindcss sorts class names into a canonical order, which removes an entire category of review comment.
npm install -D prettier prettier-plugin-tailwindcss{
"plugins": ["prettier-plugin-tailwindcss"]
}Before and after:
<!-- as typed -->
<div class="text-white p-4 flex bg-indigo-600 items-center rounded-lg">
<!-- after formatting -->
<div class="flex items-center rounded-lg bg-indigo-600 p-4 text-white">Development workflow#
- Run the dev server. Tailwind rebuilds on save; changes appear without a full reload in Vite-based setups.
- Write markup first. Compose utilities directly. Do not reach for custom CSS until a pattern repeats.
- Extract components, not classes. When markup repeats, make it a component in your framework — see Utility-First CSS.
- Promote to tokens. When a value repeats across components, add it to
@theme. - Build for production. Minify and verify the bundle before shipping.
Inspecting generated CSS#
Hovering a class in IntelliSense shows its CSS. To see everything Tailwind produced:
npx @tailwindcss/cli -i ./src/styles/app.css -o ./debug.cssSearch debug.css for a class to confirm it was generated. If it is missing, source detection did not see the file that uses it.
Ignoring build output#
node_modules/
dist/
*.localCommon mistakes#
- Recreating
tailwind.config.jsout of habit. v4 does not read it unless you add@config. Use@theme. - Importing Tailwind after your own CSS.
@import "tailwindcss"should come first so theme variables exist for the rules that follow. - Adding
autoprefixer. v4 prefixes internally; the extra plugin is redundant. - Assuming a class works because IntelliSense offered it. IntelliSense reads your theme; the build reads your source files. A class in a file Tailwind cannot see still produces nothing.
Related topics#
- Installation — get the build running
- Theme & Design Tokens — define your scales
- Functions & Directives —
@source,@utility,@config - Troubleshooting — when a class produces no CSS