Tailwind v3.0 and Hugo

I can’t successfully upgrade to Tailwind v3.0 in a Hugo project I am currently building. The initial feedback in terminal matches the steps laid out in the upgrade notes but even after correcting those issues the build still fails. I have PostCSS 8 installed.

Nothing was changed so I have just re-installed v2 and its fine again. I don’t really need to upgrade but curious to know the source of the issue so I can use v3 sometime soon.

If anyone can shed any light on this it would be gratefully received. Thank you

Initial error

Error: Error building site: POSTCSS: failed to transform "css/main.css" (text/css): warn - The `purge`/`content` options have changed in Tailwind CSS v3.0.
warn - Update your configuration file to eliminate this warning...

Error after correcting the purge content setting (I think this is the same error I got when I tried using JIT when its was released)

Error: Error building site: POSTCSS: failed to transform "css/main.css" (text/css): Error: ENOENT: no such file or directory...

I haven’t tested v3.0 – but I suspect that they have JIT compiler enabled by default. The short story is that you need to turn that off (for now, anyway – we need to do some work on the Hugo side for that to work).


I am also trying 3.0 (no success so far). Did you move the main.css around to see if there is a location where it can be found? I also always add the location to the main.css like /* static */ or whatever.

Will do more testing today.

As far as I know, the JIT build mode cannot be disabled, starting from 3.0+

Yep, it’s JIT-only.

I found a type of ugly workaround for now. I am on Windows and use VS Code.

My head.html has this lines:

{{ $styles := resources.Get "/css/style.css" | postCSS }}
{{ if .Site.IsServer }}
  <link rel="stylesheet" href="{{ $styles.RelPermalink }}"/>
{{ else }}
  {{ $styles := $styles | minify | fingerprint | resources.PostProcess }}
  <link rel="stylesheet" href="{{ $styles.RelPermalink }}" integrity="{{ $styles.Data.Integrity }}"/>
{{ end }}

In Terminal I do a:
npx tailwindcss -i ./assets/css/main.css -o ./assets/css/output.css --watch

Then I open another terminal and do: hugo server

Now I can see the changes in localhost:1313

To get the /public/ folder I do a hugo --minify

And I get the minified fingerprinted output.css (much longer file name than that of course)

So for now I need to use two running terminals. I am sure there is a more elegant way, but that is beyond my current knowledge.

I also found a one-command workaround:

Install concurrently
npm i -D concurrently

"scripts": {
    "start": "concurrently npm:watch:*",
    "watch:tw": "tailwindcss -i ./assets/css/main.css -o ./assets/css/style.css --watch",
    "watch:hugo": "hugo server",
    "build": "hugo --minify"

npm start start

Here a updated slightly refined version, it works fine. Install and go:

Praveen Juge’s workaround (as mentioned and amended herein) still apparently works with TWCSS 3.0:

At a reader’s request, I gave it a shot with 3.0, too, and it worked.


Thanks for updating your hugo-twcss starter kit!

1 Like

You’re welcome. As I said, a reader asked, so … :thinking:

I have an idea about how to get Hugo work nicely with Tailwind JIT, but it’s not trivial (at least in the non-trivial setups) … I may get to it before Xmas – but looking at Tailwind’s issue tracker, there are plenty of 3.0-bugs, suggesting that staying with 2.* for another month is probably the smart thing to do :slight_smile:


Wondering, what are the issues? I ported one Hugo site to Tailwind 3.0 and it works perfectly fine. So far my repo seem to work with no bugs found.

I think ideally the goal would be avoiding the need for an external tailwindcss -i watch process, but just letting Hugo (i.e., just hugo server) handle it directly. That works for Tailwind 2 (without JIT), where Hugo just calls PostCSS directly and that can do all the needed stuff. But 3 currently needs the external processing for the JIT to work.

1 Like

That’s correct, and there are several reasons why you’d want that.


Will it be possible to allow us to use the separate tailwindcss watcher too?

IMO there’s a huge benefit to be able to use stock tools and config files for asset management (tailwindcss, esbuild, etc.) which take an input directory and produce an output directory. Then this output directory is what gets fed into whatever tool we’re using (Hugo in this case, but this could also be Flask, Django, Rails or anything).

It basically means the individual tool using the assets doesn’t need to do anything special for TailwindCSS or any tools you use. It only expects a directory where assets exist. How they get there isn’t in the equation.

I ended up writing my previous comment before using Hugo.

I started converting my site to it today and it turns out Tailwind v3 works completely fine out of the box if you plan to use the TailwindCSS CLI to run the watcher while having it dump the output to Hugo’s assets directory which it can then fingerprint. Likewise, esbuild works too in the same way.

Having to run multiple watchers ends up not being an issue if you’re using Docker. Docker Compose can start them all up and multiplex their output to 1 terminal. If you’re not using Docker you can use something like tmux to run each watcher in its own pane / window or take advantage of the watch comand without tmux to have each watcher output its results in 1 terminal window.

1 Like

When I try to update to TWv3, I get a weird error of PostCSS locking for a stdin file or folder under my project root. That’s where usually the hugo_stats.json is located.

Start building sites … 
hugo v0.91.2+extended darwin/arm64 BuildDate=unknown
Error: Error building site: POSTCSS: failed to transform "css/styles.css" (text/css): Error: ENOENT: no such file or directory, stat '/Users/dirkolbrich/Code/_websites/dirkolbrich-static/stdin'
    at Object.statSync (node:fs:1538:3)
    at trackModified (/Users/dirkolbrich/Code/_websites/dirkolbrich-static/node_modules/tailwindcss/lib/lib/setupContextUtils.js:470:39)
    at Object.getContext (/Users/dirkolbrich/Code/_websites/dirkolbrich-static/node_modules/tailwindcss/lib/lib/setupContextUtils.js:822:5)
    at /Users/dirkolbrich/Code/_websites/dirkolbrich-static/node_modules/tailwindcss/lib/lib/setupTrackingContext.js:141:53
    at /Users/dirkolbrich/Code/_websites/dirkolbrich-static/node_modules/tailwindcss/lib/processTailwindFeatures.js:37:11
    at plugins (/Users/dirkolbrich/Code/_websites/dirkolbrich-static/node_modules/tailwindcss/lib/index.js:20:104)
    at LazyResult.runOnRoot (/Users/dirkolbrich/Code/_websites/dirkolbrich-static/node_modules/postcss/lib/lazy-result.js:339:16)
    at LazyResult.runAsync (/Users/dirkolbrich/Code/_websites/dirkolbrich-static/node_modules/postcss/lib/lazy-result.js:393:26)
    at async Promise.all (index 0) {
  errno: -2,
  syscall: 'stat',
  code: 'ENOENT',
  path: '/Users/dirkolbrich/Code/_websites/dirkolbrich-static/stdin'
Built in 436 ms

Does anyone what this is all about?

The following configuration in my head.html partial:

<!-- Hugo Pipes for processing Tailwind CSS -->
{{- if .Site.IsServer }}
    {{- $style := resources.Get "css/styles.css" | postCSS (dict "config" "./assets/css/dev/postcss.config.js") -}}
    <link rel="stylesheet" href="{{ $style.RelPermalink }}">
{{ else }}
    {{- $style := resources.Get "css/styles.css" | postCSS (dict "config" "./assets/css/postcss.config.js") | minify | fingerprint -}}
    <link rel="stylesheet" href="{{ $style.Permalink }}">
{{ end -}}

The above stated error comes either if I run hugo server or hugo.

See the article linked in Tailwind v3.0 and Hugo - #6 by bwintx for info about the stdin issue and how Praveen Juge’s workaround solves it for all versions of Tailwind using JIT.

@bwintx thanks for the heads up and your thorough explanation. I could have come to the more in depth view by myself if I would have dug deeper and LMDDGTFY. And just now someone filed an issue to the TailwindCSS project with exactly the same error and the origin of the stdin error.

Weird thing, as at the time of writing my initial post your referenced blog post just showed the title but no content was available. Now it works, must have been an error on MyMachine™.

1 Like

@dirkolbrich you’re welcome. And, yes, I’ve been watching that GitHub issue, and hope the new info about stdin will lead to a real fix. While Mr. Juge’s workaround is brilliant, it is still a workaround and not the final solution. As for why my page wasn’t working at the time: was my error. I had an {{end}} inside a div but it triggered this glitch only under certain circumstances — which, as you can guess, this page met. Oops. Sorry!

Just trying to see what the known state is of tailwind 3 on Hugo.

Best place to watch is really Hugo Issue #8343.