This first hands-on episode: you install Tailwind CSS via the Tailwind CLI, PostCSS plugin, or framework integration, then write a minimal tailwind.config.js and set up content for JIT. You also run the development workflow with watch mode.

After understanding the architecture in episode 2, now it's time to get started quickly. Episode 3 walks you through installing Tailwind CSS via the three most common paths: the Tailwind CLI, the PostCSS plugin, and framework integration. You'll also write a minimal tailwind.config.js and run the development workflow with watch mode.
Which path you choose depends on your project. A static HTML project is fine with the CLI; a project with a bundler like Vite or a framework like Next.js usually uses PostCSS or a dedicated plugin. The end result is identical: a single static CSS file produced at build time.
The simplest approach with the least bundler dependence:
npm install -D tailwindcss
npx tailwindcss initThen builds are done with the -i flag for input and -o for output. This CLI is ideal for static HTML projects and quick prototypes. Note: in Tailwind version 4, the CLI is split into a separate @tailwindcss/cli package — always check the docs for the release you use.
For projects that already use PostCSS — for example Vite or custom build tooling — install Tailwind as a PostCSS plugin:
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -pThe -p flag also creates postcss.config.js:
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};Tailwind then runs as part of the bundler pipeline, and autoprefixer adds browser prefixes automatically.
Modern frameworks offer cleaner integrations. Next.js and SvelteKit use PostCSS as above; Vite has an official plugin; Astro also uses PostCSS. We'll break down per-framework integration in episode 18 — for now, just know they all still produce the same static CSS.
A minimal config needs just three main keys:
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./index.html", "./src/**/*.{html,js,ts,jsx,tsx}"],
theme: {
extend: {},
},
plugins: [],
};The most critical part is content. The more accurate the glob, the faster the scan and the smaller the generated CSS. Don't include folders you don't need, like node_modules or build directories.
Create an input CSS file with the core directives:
@tailwind base;
@tailwind components;
@tailwind utilities;Then run a basic build:
npx tailwindcss -i src/styles.css -o dist/output.cssFor development, use --watch so the build reruns automatically whenever a file changes:
npx tailwindcss -i src/styles.css -o dist/output.css --watchThe generated dist/output.css file is what you link in your HTML:
<link rel="stylesheet" href="dist/output.css" />The command npx tailwindcss -i src/styles.css -o dist/output.css --watch will accompany you throughout the series. In production, --watch is dropped and the build runs once on CI — a topic for episode 13.
Info
Never edit dist/output.css manually. That file is a build artifact and gets overwritten every time Tailwind runs. All changes go into the source CSS and the utility classes in your markup.
Episode 3 completes the practical setup: you know the three installation paths (CLI, PostCSS, framework), how to write a minimal config with the right content, and how to run the build workflow with watch mode.
Key takeaways:
content determines which files JIT scans — keep it narrow.@tailwind base, components, utilities directives must be in your input CSS.-i and -o set the input and output files.--watch enables automatic rebuilds for development.Next, in episode 4, we'll enter the utility-first workflow: writing the most commonly used basic classes — typography, spacing, sizing, display, flexbox, grid, and state variants like hover and focus. It's time to write lots of markup.