← Back to blogYouTube Video

October 23, 2026 • By

How to use Tailwind CSS v4 with Django 6, no package needed

Can't play the video or having issues? Here's the direct link.

The short version

  • You can use Tailwind v4 with Django without an API or a Django package: the Tailwind CLI compiles a CSS file into your app's static folder, and your templates load it with the static tag.
  • Link the compiled output.css in your templates, not the globals.css input file, which only holds Tailwind's @import line.
  • Tailwind v4 needs no config file. It scans your project for class names, Django templates included, and only generates CSS for the classes it finds.
  • While you work, run the Tailwind watcher and Django's runserver in two terminals. The watcher rebuilds the CSS every time you save a template.
  • Before you deploy, build the CSS with --minify first and run collectstatic after it, so the fresh output.css is what gets collected.

To use Tailwind CSS v4 with Django, run the Tailwind CLI in watch mode so it compiles a CSS file into your app's static folder, and load that compiled file in your templates with the static tag. You don't need a REST API or a Django package for it.

Below I set up a fresh project step by step and cover what to run before you deploy. I tested every file on this page with Django 6.1.2 and Tailwind 4.3.3. The video above covers the same setup on Django 6.0.

You don't need an API to use npm tools with Django

I see a lot of people struggle to get Django, or any Python framework, working with Node.js tools. Many of them assume the only way is to build a backend API with Django REST Framework and put a React app in front of it. For Tailwind that's massive overkill.

Tailwind is a build tool. It reads your files for class names and writes a CSS file with the styles for them. Django already knows how to serve static files and render templates. The two meet at a single file on disk: Tailwind writes output.css, and your template links to it. Neither one has to know the other exists, and you keep Django templates and everything else you like about Django.

The same idea works for any npm tool whose output is a file. Run it from an npm script that writes into a static folder, and load the result from your templates.

How Tailwind v4 finds your classes

Tailwind v4 dropped the tailwind.config.js file. You configure it from CSS instead, and the whole setup is one line in a CSS file:

@import "tailwindcss";

When the CLI runs, it scans the files in the folder you run it from for anything that looks like a class name, and generates CSS only for the classes it finds. It skips node_modules and anything in your .gitignore. Django templates are plain text files, so it picks up the classes in them without any setup. My demo's minified CSS came out at under 5 KB, because the template only uses four classes.

This setup vs django-tailwind vs django-tailwind-cli

If you search for this, you'll find two Django packages that wrap Tailwind for you. Here's how they compare with doing it by hand:

Tailwind CLI by hand (this page)django-tailwinddjango-tailwind-cli
Needs Node.jsYesOnly in npm modeNo
How Tailwind gets installednpm install or bun addmanage.py tailwind installDownloads the standalone CLI on first run
Extra Django appNoYes, a theme appNo
How you run itAn npm script plus runservermanage.py tailwind dev or tailwind startmanage.py tailwind runserver
Tailwind pluginsAny npm pluginAll in npm mode, only DaisyUI in standalone modeDaisyUI is built in

Both packages work. The by-hand version is what I show in the video: two npm packages and one script. It has nothing to learn beyond Tailwind's own docs, and if you add another npm tool to the project later, it runs the same way.

Set up the project

I use uv for every Python project. It manages the virtual environment and the dependencies, and it's much faster than pip install. For the npm side I use Bun, because it installs packages faster than npm. Plain npm works the same way if you prefer it.

Django 6 needs Python 3.12 or newer. Create the Django project, then set up uv and npm inside it:

uvx --from django django-admin startproject tailwind_integration
cd tailwind_integration
uv init
uv add django
npm init -y
bun add tailwindcss @tailwindcss/cli

uv init also creates a main.py that Django doesn't need, so delete it. The @tailwindcss/cli package is what gives you the tailwindcss command. In v4 it's a separate package from tailwindcss itself.

Now create an app with a templates folder and a static folder:

uv run python manage.py startapp app
mkdir -p app/templates app/static

Here's the finished project, without the generated files we don't touch:

tailwind_integration/
├── app/
│   ├── static/
│   │   ├── globals.css
│   │   └── output.css
│   └── templates/
│       └── base.html
├── tailwind_integration/
│   ├── settings.py
│   └── urls.py
├── manage.py
├── package.json
└── pyproject.toml

output.css doesn't exist yet. Tailwind creates it the first time it runs.

Register the app and add a URL

Add the app to INSTALLED_APPS in tailwind_integration/settings.py:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app',
]

Django only looks in an app's templates and static folders once the app is installed, so if you skip this, it can't find the template or the CSS.

Then replace tailwind_integration/urls.py with this:

from django.contrib import admin
from django.urls import path
from django.views.generic import TemplateView

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', TemplateView.as_view(template_name='base.html')),
]

TemplateView renders a template without a view function, which is all a test page needs.

The template

Here's app/templates/base.html:

{% load static %}
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Django + Tailwind</title>
  <link rel="stylesheet" href="{% static 'output.css' %}">
</head>
<body class="p-8">
  <h1 class="text-4xl font-bold text-red-500">Hello, world!</h1>
</body>
</html>

{% load static %} at the top makes the static tag available, and the stylesheet link uses it to point at output.css. Link the compiled file, not the globals.css you write. globals.css only holds an @import line that means nothing to a browser. I linked the wrong one at first in the video too.

The classes on the heading are only there so you can see at a glance that Tailwind is working.

The Tailwind input and the npm script

app/static/globals.css is the input file Tailwind reads, and it holds the one line from earlier:

@import "tailwindcss";

Add your own CSS below it if you need any. Then add two scripts to package.json, one for development and one for production:

{
  "name": "tailwind_integration",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "css:watch": "tailwindcss -i app/static/globals.css -o app/static/output.css --watch",
    "css:build": "tailwindcss -i app/static/globals.css -o app/static/output.css --minify"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "type": "commonjs",
  "dependencies": {
    "@tailwindcss/cli": "^4.3.3",
    "tailwindcss": "^4.3.3"
  }
}

-i is the input file and -o is the output. --watch keeps the CLI running and rebuilds output.css every time you save a file that could contain classes, templates included. --minify makes the production file as small as possible.

Run it

You need two terminals, both in the project folder. In the first, start the Tailwind watcher:

npm run css:watch

It prints "Done" with a time in milliseconds and keeps running. bun run css:watch does the same thing.

In the second, start Django:

uv run python manage.py runserver

If you'd rather activate the virtual environment with source .venv/bin/activate, plain python manage.py runserver works too. Just make sure the Django terminal is using the right environment.

Open http://127.0.0.1:8000. You should see "Hello, world!" in large, bold red text with some padding around the page. Now add a class to the heading, say underline, and save. The watcher rebuilds the CSS in a few milliseconds, and when you refresh the page, the heading is underlined.

If the page errors or the text shows up unstyled, look for the two typos I made in the video. I forgot the closing %} on the static tag, and I wrote font-4xl instead of text-4xl. Tailwind silently ignores a class that doesn't exist, so a typo in a class name just means no style.

Also check that the watcher terminal is still running. The watcher stops when its input stream closes. In a terminal that never happens, but if you start it from a process manager or a container with no terminal attached, it exits straight away. Use --watch=always there to keep it running.

Before you deploy

In production, Django doesn't serve static files from your apps. collectstatic copies them all into one folder for your web server or a package like WhiteNoise to serve. Set where that folder goes in settings.py:

STATIC_URL = 'static/'
STATIC_ROOT = BASE_DIR / 'staticfiles'

Then build the CSS before you collect:

npm run css:build
uv run python manage.py collectstatic --noinput

Order matters here. If collectstatic runs first, it copies whatever output.css was on disk, which could be stale or missing. Put both lines in your deploy script so the build server does it every time.

One more thing: the .gitignore that uv init creates only covers Python files, so add node_modules/ to it yourself.

Keep each tool doing its own job

uv handles the Python side and Bun handles the npm side, in the same repo, and neither gets in the other's way. Tailwind builds a CSS file and Django serves it, and that's all there is to it. You don't need a separate framework or an API for this. You keep writing Django templates and using every Django feature you already know, and Tailwind runs next to them.

Video transcript

Show
Test, test, test, test, test, test, test. Alright guys, welcome back to another video. So, as many of you know, Django 6.0 just came out recently, just a couple of weeks ago. And in this video, I want to teach you how to integrate Django with Tailwind. And the reason I'm making this video is because I see a lot of people who struggle to integrate Django or Python frameworks with Node.js technologies, right? And hopefully, by integrating Django with Tailwind in this video, I can explain that entire process and make it a lot easier for you guys to integrate npm packages into your Django application. This is not like building a backend API with Django and Django REST and then integrating that with some React front-end application or something. No, this is literally integrating Tailwind into your Django templates. Let's get started. Step one, create a new Django project using the Django admin command, start project, and then just give it a name. I'll just call this Tailwind integration over here. CD into it, and here you have your Django project. Now, one extra thing I'm going to do over here is I'm going to use UV to initialize my project. This is a separate tool. UV is what I use to manage all of my Python projects and their virtual environments and dependencies and everything. It's much faster and better than pip install, and I highly recommend you guys start using it as well. Now, we're going to install Django into this virtual environment as well, and we're also going to initialize an empty npm package over here. We'll just use the default options for everything, and now this is the project that we have so far. Now, let's install Tailwind over here. I'm going to use Bun to install this just because it's a lot faster than npm, and we're going to install Tailwind CSS and also the CLI to use Tailwind CSS. Now, let's create our first Django app. I'll just call this app. Add it to the list of installed apps as well so we can use it, and then let's create a template in here. Create a templates directory and create a base.html over here. Let's create a heading over here that has a couple of Tailwind classes so we can actually tell that this is working. Let's say text-red-500, font-4xl or something, and then let's just print a hello world over here. Let's also go up in the head tag over here and link a CSS file. This will be in the static folder, and we call this globals. Okay, and let's also import the static tag up at the top of our template. Now, let's create a static directory in this app and create the globals.css file, and then let's import Tailwind CSS over here. Now, let's add a CSS watch command over here. CSS watch, there we go. And we will call npx tailwindcss. We'll pass in an input, which will be app/static/globals.css, and also pass in an output that will be app/static/output.css, and then make sure to watch this file for any changes. Now, if I run this command by using npm run css watch, it's going to run Tailwind and watch the file for any changes, and it's going to create the output.css file, which has all of our CSS over here. Now, we just need to make sure that we're importing the correct file from in our templates, and over here, this should be output.css instead of globals.css. Now, if I just go over to urls.py and just add a simple URL over here, we can use a simple TemplateView, which we can import from django.views.generic, and just pass in a template called base. There we go. Template name. Make sure to add the name of the argument over here. Let's let this CSS watch command run over here and open up a new terminal. Make sure you're in the correct virtual environment, and then let's run python manage.py runserver. Okay, quick typo to fix. I forgot to close the static tag over here. Make sure you do that. Don't be me. And also, this class is supposed to be text-4xl instead of font-4xl. And if you go back to our page over here, you'll see that the Tailwind classes are being applied perfectly fine. So that's how you can integrate Tailwind into your Django project without having to create a separate framework or a separate API, and still continue to use Django templates and all the other Django features that we all love. If you like this video, press like, comment, subscribe, all of those wonderful things. And a quick self-promotion plug over here. I'm a freelance web developer, and I build web apps and mobile apps for people. If this is something you're interested in, or if you know someone who's interested in this and you want to work with me on some sort of a project, you'll find the top link in the description, which will take you to book a call with me, and then we can discuss everything that you want and we can start working on it. That's all from me for today, guys. Thank you for watching, and I'll see you in the next video.

Share this article

Hassan Aziz pointing up

Dude, you’re at the bottom of my landing page.

Just book a call already if you’re that interested.

You scrolled all the way here.