2025-05-11
Debugging Slow Docker Builds in Next.js (Tailwind CSS v4.1 Fix Inside)
Docker builds on macOS shouldn't crawl—but they often do when Tailwind gets chatty. Here's why they slow down and the quick fix that slashes build time.
If you're working with monorepos, check out my Fun with Monorepos guide for setup tips. Curious about my full dev setup? See What I Use. For Node.js version management with Bun or Fish shell, see Using asdf to solve NVM for Fish.
1 — Why Docker Builds Crawl
Tailwind's Oxide engine (Tailwind CSS v4 announcement) can read tens of thousands of files every build, and Docker‑for‑Mac's overlay filesystem is painfully slow at large directory walks (Docker‑for‑Mac filesystem performance issue).
2 — Baseline the Pain
time bun run build # local
time docker build . # container
Anything over a 3× delta is worth digging into.
3 — Turn the Lights On
Add this just before the expensive layer in your Dockerfile
:
ENV DEBUG=*
RUN bun run build
Pipe BuildKit logs to avoid the console clamp:
docker buildx build --progress=plain . | tee build.log
4 — Trace the Bottleneck
Look through build.log
for:
tailwindcss_oxide: Reading … file(s)
spam- Long
t=
durations in Next.js output - Repeated cache misses
These clues point to disk I/O churn, not CPU limits.
5 — Fix: Upgrade Tailwind CSS → v4.1+
Tailwind v4 introduced Oxide for speed (Oxide engine preview), but v4.1 trims unnecessary scans, skips irrelevant files, and threads its work (v4.1 release notes, community reports). Upgrade and rebuild:
bun add tailwindcss@latest # or npm install tailwindcss@latest
docker build .
My main build step dropped 85 s → ≈30 s, with the full image down from 140 s → < 60s.
6 — Extra Optimizations (Optional)
Tweak | Why it Helps |
---|---|
.dockerignore node_modules , .next , dist , logs , test | Smaller context, faster COPY |
Persist .next/cache | Warm cache beats cold starts |
Narrow globs or use @source not to ignore big paths (new in v4.1) | Fewer files scanned |
Raise BuildKit log caps with BUILDKIT_STEP_LOG_MAX_SIZE/SPEED | No more clipped logs |
Bonus Tip: Debugging with Verbose Logs
When you enable verbose logs (DEBUG=*
), Docker may throttle output at around 200 KiB/s, showing [output clipped, log limit …]
(BuildKit log‑size issue, Buildx discussion). This doesn't directly cause slow builds, but it can make debugging harder by hiding logs. If you see [output clipped]
, try piping BuildKit logs to plain output or raising the BUILDKIT_STEP_LOG_MAX_SIZE
and BUILDKIT_STEP_LOG_MAX_SPEED
environment variables. See Stack Overflow example for more details.
7 — Conclusion
Slow Docker builds are almost always an I/O problem. Light up verbose logs, pinpoint the choke point, and upgrade the offending dependency. For Next.js projects, the single most effective change is moving to Tailwind CSS v4.1+—everything else is just cleanup.