Use with WhiteNoise

WhiteNoise and django-tailwind-cli need no special configuration to work together — the defaults of both packages already fit. What follows is a working setup plus the places where the two packages surprise people.

Sample configuration

# settings.py

INSTALLED_APPS = [
    # ...
    "whitenoise.runserver_nostatic",  # before django.contrib.staticfiles
    "django.contrib.staticfiles",
    "django_tailwind_cli",
]

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "whitenoise.middleware.WhiteNoiseMiddleware",  # directly after SecurityMiddleware
    # ...
]

STATIC_URL = "/static/"
STATIC_ROOT = BASE_DIR / "static"  # collectstatic target, not a source directory
STATICFILES_DIRS = [BASE_DIR / "assets"]  # where the CLI writes css/tailwind.css

STORAGES = {
    "staticfiles": {
        "BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage",
    },
}

No TAILWIND_CLI_* setting is required. The defaults put the source CSS in <BASE_DIR>/.django_tailwind_cli/source.css, outside the static directories, and the build output in <STATICFILES_DIRS[0]>/css/tailwind.css — exactly what the manifest storage expects to collect. If you override TAILWIND_CLI_DIST_CSS, that path is the one the rest of this page refers to.

Build the CSS before collectstatic

python manage.py tailwind build
python manage.py collectstatic --noinput

Getting this order wrong does not fail the build. collectstatic succeeds, writes a manifest without an entry for the stylesheet, and the site breaks on the first request that renders {% tailwind_css %}:

ValueError: Missing staticfiles manifest entry for 'css/tailwind.css'

The quoted path is whatever TAILWIND_CLI_DIST_CSS resolves to.

Keep the source CSS out of the static directories

If TAILWIND_CLI_SRC_CSS points at a file inside STATICFILES_DIRS, collectstatic fails:

whitenoise.storage.MissingFileError: The file 'css/tailwindcss' could not be found with
<whitenoise.storage.CompressedManifestStaticFilesStorage object at 0x…>.

The CSS file 'css/source.css' references a file which could not be found:
  css/tailwindcss

Django’s ManifestStaticFilesStorage, which WhiteNoise’s storage backend extends, rewrites every @import "…" statement in every collected CSS file and expects the target to be another static file. @import "tailwindcss"; names a package, not a file, so the lookup fails. The missing name is reported relative to the source file, so it reads tailwindcss for a source CSS at the root of a static directory and css/tailwindcss for one in a css/ subdirectory.

Put a hand-written source CSS anywhere outside the static directories — the default location already is. The same applies to every source file listed in TAILWIND_CLI_CSS_MAP.

A Django system check reports this as django_tailwind_cli.W001, so you do not have to wait for a deploy to find out — it runs on manage.py check, on runserver, and on every manage.py tailwind subcommand. It is a warning rather than an error because without a manifest storage backend the only consequence is that the source file gets published alongside the build output; silence it through SILENCED_SYSTEM_CHECKS if that is what you want.

Development

whitenoise.runserver_nostatic hands static files to WhiteNoiseMiddleware during development. WHITENOISE_AUTOREFRESH and WHITENOISE_USE_FINDERS both default to settings.DEBUG, so a stylesheet rebuilt by tailwind runserver or tailwind watch is picked up on the next request without restarting the server. Pinning WHITENOISE_AUTOREFRESH = False during development serves the stale file instead.

django-project-starter is a working example of this setup.