Using Tailwind CSS in Flask – Modern Setup Guide (2026)
Step-by-step guide to integrating Tailwind CSS with Flask using the official CLI, automatic purging, and a smooth dev workflow.
Tailwind CSS has become the go-to utility-first CSS framework for rapid UI development. Pairing it with Flask — Python's lightweight web framework — gives you fast backend + beautiful, responsive frontends without fighting CSS files.
In this guide we'll set up a clean, production-ready integration using Tailwind CSS v4 (or v3) workflow with the official CLI, proper content scanning, and auto-rebuild during development.
Prerequisites
- Python 3.10+
- Node.js 18+ (with npm)
- Basic Flask knowledge
Project Structure (Recommended)
my-flask-app/
├── app.py # or app/__init__.py if using app factory
├── tailwind.config.js
├── input.css # or static/src/input.css
├── package.json
├── static/
│ └── css/
│ └── output.css # compiled + purged Tailwind file
└── templates/
└── index.html
Step 1: Create a Basic Flask App
# app.py
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/")
def home():
return render_template("index.html")
if __name__ == "__main__":
app.run(debug=True)
<!-- templates/index.html -->
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Flask + Tailwind</title>
<link href="{{ url_for('static', filename='css/output.css') }}" rel="stylesheet">
</head>
<body class="bg-gray-50 min-h-screen antialiased">
<div class="container mx-auto px-4 py-16">
<h1 class="text-5xl font-bold text-indigo-700 mb-6">
Hello from Flask + Tailwind CSS
</h1>
<p class="text-xl text-gray-700 max-w-2xl">
Rapidly build modern interfaces without ever leaving your Python comfort zone.
</p>
</div>
</body>
</html>
At this point nothing looks styled yet — let's add Tailwind.
Step 2: Initialize Node.js & Install Tailwind
In the root of your project:
npm init -y
npm install -D tailwindcss
npx tailwindcss init
Note (2026 update): Tailwind v4 no longer requires PostCSS by default when using the standalone CLI. The above is the simplest modern way.
Step 3: Configure tailwind.config.js
Update tailwind.config.js to scan your Jinja templates:
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./templates/**/*.html", // all Jinja templates
"./app/templates/**/*.html", // if using blueprints / app factory
],
theme: {
extend: {
// Optional: customize colors, fonts, etc.
colors: {
primary: '#4f46e5',
},
},
},
plugins: [
// require('@tailwindcss/typography'),
// require('@tailwindcss/forms'),
],
}
Step 4: Create Input CSS File
Create input.css (you can put it in root or static/src/input.css):
/* input.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
Step 5: Build & Watch Tailwind CSS
Add these scripts to package.json:
{
"scripts": {
"build:css": "tailwindcss -i ./input.css -o ./static/css/output.css --minify",
"watch:css": "tailwindcss -i ./input.css -o ./static/css/output.css --watch"
}
}
Now run in separate terminals:
# Terminal 1 – Flask dev server
flask run --debug
# or python app.py
# Terminal 2 – Tailwind watcher
npm run watch:css
Every time you add/remove Tailwind classes in your templates, the output.css file updates automatically (and is purged to ~10–30 KB in production).
Bonus: One-command dev experience (using concurrently)
npm install -D concurrently
Update package.json scripts:
"dev": "concurrently \"npm run watch:css\" \"flask run --debug\""
Then just run:
npm run dev
Both Flask and Tailwind watch & reload happen together.
Production Build
Just run:
npm run build:css
The --minify flag ensures smallest possible file. Include static/css/output.css in your base template as usual.
Optional: Using DaisyUI, Flowbite, Preline, etc.
Many component libraries work great on top of Tailwind. Example with DaisyUI:
npm install -D daisyui@latest
// tailwind.config.js
plugins: [
require('daisyui'),
],
Then use classes like btn btn-primary, card, navbar, etc.
Common Pitfalls & Tips
- Classes not appearing? → Make sure the class is actually written in a
.htmlfile that is scanned (not in Python strings). - Large CSS file in dev? → Normal — Tailwind only purges in production builds or when
--minifyis used. - Jinja
{% %}blocks → Tailwind scans them correctly as long as they're inside content paths. - Blueprints? → Add
./blueprints/*/templates/**/*.htmlto content array. - Tailwind v4 standalone CLI → If you want zero PostCSS:
npx tailwindcss@latest initstill works great.
Final Thoughts
Combining Flask + Tailwind gives you:
- Lightning-fast prototyping
- Zero context-switching between backend & frontend
- Tiny production CSS bundles
- Full control over design without fighting CSS specificity
Comments
The layout of this blog is incredibly clean. The sticky TOC works perfectly on my ultra-wide monitor.
Are you using DaisyUI for the theme switching as well? Would love to see a post on that.
Thanks for the share to X button logic, saved me a lot of time!