Styles aren't generated when building a Docker image for ARM64 on a 2019 Intel MacBook Pro
Closed this issue · 25 comments
What version of Tailwind CSS are you using?
v4.1.3
What build tool (or framework if it abstracts the build tool) are you using?
Rails 8.0.2
What version of Node.js are you using?
What browser are you using?
Chrome
What operating system are you using?
macOS -> ARM64
Describe your issue
I've prepared detailed steps you can follow.
-
I'm on a MacBook Pro 2019 (Intel):
% arch i386 % uname Darwin -
Generate a new Rails 8 app with Tailwind enabled (zip attached):
rails new TailwindOnARM --css tailwind -
Scaffold a resource that uses Tailwind classes:
rails g scaffold Post -
Start the dev server and check that Tailwind styling is applied (https://localhost:3000/posts):
bin/dev
-
Build and push a Docker image for ARM64:
docker buildx build --platform linux/arm64 -t kyrylo/tailwind-on-arm:latest --push . -
On an ARM server (I use Hetzner CAX11), install Docker, then run the image:
docker run -d -p 80:80 -e RAILS_MASTER_KEY=90279f1e5d289cb437ba0c2f959a2ea5 --name tailwind_on_arm kyrylo/tailwind-on-arm -
Check the result at
http://<IP-ADDRESS>/postsand notice that Tailwind styling is not applied:Screenshot application.css 

I'm happy to help debug this further. You can pull my image from Docker Hub so you don't have to build it yourself.
Hey! Do you have any debug logs from the build step? There are a lot of components in your repro (rails/tailwind gem/docker) so it's hard to know what's going on. Perhaps you can try to run only the Tailwind CSS standalone build in isolation in the Dockerfile for a repro?
Hey everyone, having similar issue as it used to work before. Building a web app with ruby on rails 8. I tried to narrow it down as far as I could.
My setup:
- Docker Desktop (Current version: 4.38.0 (181591)) for development on Mac (M2)
- Tailwind v4.1 for styling using tailwindcss-rails 4.2.2 and tailwindcss-ruby-4.1.4-aarch64-linux-gnu (for Mac)
- Using docker buildx for pushing the image on a self-hosted registry as the server architecture is a linux/amd64 (Debian).
Dev:
When starting the web app in dev container on my mac (dev container is started via docker compose up) the output on localhost:3000 is as expected and tailwind.css contains all css classes.
Prod:
As my server runs under an other architecture (linux/amd64) I need to build the image and push it to self-hosted registry with docker buildx build --platform linux/amd64 --push -t registry.******.com/myapp:latest . After starting the container on the server I checked the tailwind.css in browser and saw that a lot of css-classes were missing.
During the build within the standard dockerfile, which is generated when you create a new project, the line below compiles the assets:
# Precompiling assets for production without requiring secret RAILS_MASTER_KEY
RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile
Underneath assets:precompile the tailwindcss:build-command is executed which executes tailwind -i path/to/application.css -o path/to/tailwind.css
It seems that tailwind is not parsing all the files like mentioned in the doc when architecture is not the same as the host machine
What I tried so far:
- Building image with
docker build . -t testand inspected the content of the css-file usingdocker exec -it test bash--> css-file is correct and corresponds to the one in dev environment. - Building image locally (not pushing it to registry for inspection) with
docker buildx build --platform linux/amd64 --load -t test .and same issue as above after inspecting the css-file. - I checked the compiled gem in the image and they correspond to the defined architecture (linux/amd64)
- I tried to add --verbose to assets:precompile but couldn't find any infos about errors.
- I tried to pass the paths to scan (
-c "app/views/*") but it didn't work as the tailwindcss-rails gem doesn't expose the option (only -i and -o are exposed). Anyway, this shouldn't be necessary as tailwind should scan all files (excluding the ones mentioned in the doc) starting from project-level. - I tried to set the source explicitly (doc). I made sure that non of the file which are needed for the generation of the tailwind.css are in my .gitignore-file.
As mentioned before in rails there are two gems for tailwind:
- tailwindcss-ruby based on the informations on github is just a simple wrapper around tailwind
- tailwindcss-rails is dependent of the aforementioned gem
Question:
Is the problem related to docker buildx or is related to tailwind? I don't have enough experience as I just started programming some month ago.
Thanks for any further infos / suggestions
Hi, I'm the maintainer of tailwindcss-rails and tailwindcss-ruby, and I've received a few bug reports about this issue. I've been unable to reproduce this on my hardware, and so I have been asking affected users to report this upstream (here).
Here's what I think is happening: on some x86_64 hardware (but maybe not all chips? I certainly can't repro), running the arm64 tailwindcss CLI while building an arm64 docker image fails in a mysterious way.
In an attempt to try to simplify this, I'm going to guess at a simple repro, and I have to ask @kyrylo and @xhayoz and others to tell me if this reproduces the issue.
Here is a self-contained script that should repro on some hardware if I'm guessing correctly:
#!/usr/bin/env bash
# download binaries
wget -q -c https://github.com/tailwindlabs/tailwindcss/releases/download/v4.1.4/tailwindcss-linux-arm64
wget -q -c https://github.com/tailwindlabs/tailwindcss/releases/download/v4.1.4/tailwindcss-linux-x64
# set up target html
cat > test.html <<EOF
<html>
<h1 class="py-2 px-3 text-green-500">Hello</h1>
</html>
EOF
# set up the script we'll run in the container
cat > test.sh <<EOF
#!/usr/bin/env bash
uname -a
if uname -m | fgrep aarch64 ; then
bin=./tailwindcss-linux-arm64
else
bin=./tailwindcss-linux-x64
fi
rm -f test.css
set -x
DEBUG=1 \$bin -o test.css
cat test.css | fgrep -C3 text-green-500
EOF
# run tailwind in the container
chmod +x tailwindcss-linux-* test.sh
docker run --mount=type=bind,source=$(pwd),target=/repro -w /repro --platform=linux/x86_64 ruby:3.4 ./test.sh
docker run --mount=type=bind,source=$(pwd),target=/repro -w /repro --platform=linux/arm64 ruby:3.4 ./test.shWhen I run this on my x86_64 development machine, here's what I see as output:
$ ./runme.sh
Unable to find image 'ruby:3.4' locally
3.4: Pulling from library/ruby
Digest: sha256:07c880a5e0fd72fa6cf0ff353633c488899082839578776201266e5f9fa95de0
Status: Downloaded newer image for ruby:3.4
Linux 3bc01477206e 6.11.0-1004-lowlatency #4-Ubuntu SMP PREEMPT_DYNAMIC Mon Sep 30 10:54:09 UTC 2024 x86_64 GNU/Linux
+ DEBUG=1
+ ./tailwindcss-linux-x64 -o test.css
≈ tailwindcss v4.1.4
Done in 558ms
[559.32ms] [@tailwindcss/cli] (initial build)
[ 14.10ms] ↳ Setup compiler
[453.22ms] ↳ Scan for candidates
[ 77.24ms] ↳ Build CSS
[ 13.81ms] ↳ Write output
+ cat test.css
+ fgrep -C3 text-green-500
.text-\[rgba\(255\,255\,255\,0\.87\)\] {
color: rgba(255,255,255,0.87);
}
.text-green-500 {
color: var(--color-green-500);
}
.capitalize {
Unable to find image 'ruby:3.4' locally
3.4: Pulling from library/ruby
Digest: sha256:07c880a5e0fd72fa6cf0ff353633c488899082839578776201266e5f9fa95de0
Status: Downloaded newer image for ruby:3.4
Linux a9ea127cd86c 6.11.0-1004-lowlatency #4-Ubuntu SMP PREEMPT_DYNAMIC Mon Sep 30 10:54:09 UTC 2024 aarch64 GNU/Linux
aarch64
+ DEBUG=1
+ ./tailwindcss-linux-arm64 -o test.css
≈ tailwindcss v4.1.4
Done in 6s
[6197.23ms] [@tailwindcss/cli] (initial build)
[ 280.95ms] ↳ Setup compiler
[3845.68ms] ↳ Scan for candidates
[1791.75ms] ↳ Build CSS
[ 227.93ms] ↳ Write output
+ cat test.css
+ fgrep -C3 text-green-500
.text-\[rgba\(255\,255\,255\,0\.87\)\] {
color: rgba(255,255,255,0.87);
}
.text-green-500 {
color: var(--color-green-500);
}
.capitalize {
What do y'all get as output when you run this?
@flavorjones Thanks a lot for your help! Really appreciate it!
The script was run on a Mac M2.
Output:
xavierhayoz@MacBook-Air-XH Dev % ./runme.sh
Linux 31b37a7976a5 6.10.14-linuxkit #1 SMP Thu Mar 20 16:32:56 UTC 2025 x86_64 GNU/Linux
+ DEBUG=1
+ ./tailwindcss-linux-x64 -o test.css
≈ tailwindcss v4.1.4
Done in 5s
[5075.10ms] [@tailwindcss/cli] (initial build)
[ 162.00ms] ↳ Setup compiler
[4119.15ms] ↳ Scan for candidates
[ 650.00ms] ↳ Build CSS
[ 125.00ms] ↳ Write output
+ cat test.css
+ fgrep -C3 text-green-500
.text-\[rgba\(255\,255\,255\,0\.87\)\] {
color: rgba(255,255,255,0.87);
}
.text-green-500 {
color: var(--color-green-500);
}
.text-inherit {
Linux 2ae05eaf8c4d 6.10.14-linuxkit #1 SMP Thu Mar 20 16:32:56 UTC 2025 aarch64 GNU/Linux
aarch64
+ DEBUG=1
+ ./tailwindcss-linux-arm64 -o test.css
≈ tailwindcss v4.1.4
Done in 3s
[3422.34ms] [@tailwindcss/cli] (initial build)
[ 39.85ms] ↳ Setup compiler
[3073.49ms] ↳ Scan for candidates
[ 251.98ms] ↳ Build CSS
[ 50.09ms] ↳ Write output
+ cat test.css
+ fgrep -C3 text-green-500
.text-\[rgba\(255\,255\,255\,0\.87\)\] {
color: rgba(255,255,255,0.87);
}
.text-green-500 {
color: var(--color-green-500);
}
.text-inherit {
As far as I can tell the issue is not building the image on the same architecture (using docker build) but generating an image for an other architecture with buildx (in my case linux/amd64). I'm generating the image locally which later on is pushed on a server with an x86_64 architecture.
My Mac book specs are:
uname -a 24.4.0 Darwin Kernel Version 24.4.0: Fri Apr 11 18:33:46 PDT 2025; xxxxxxx/RELEASE_ARM64_T8112 arm64
BTW I found a workaround for my issue:
- In the Gemfile I moved
gem "tailwindcss-rails", "~> 4.0"undergroup :development do .. endblock so that I still can benefit from the watch option and puma-plugin. - I added node to my Dockerfile, installed tailwindcss via npm and executed the following command when building my image
RUN npx @tailwindcss/cli -i /rails/app/assets/tailwind/application.css -o /rails/app/assets/builds/tailwind.css --minify
It's maybe not the best way but it works.
Thank you @flavorjones for your efforts in debugging this!
For extensive testing, I ran it on my laptop with 2 Docker engines and a Hetzner Arm64 box. Here are my results.
Host: MacBook 2019 (Intel) (OrbStack Engine)
% uname -a
Darwin Kyrylos-MacBook-Pro.local 22.3.0 Darwin Kernel Version 22.3.0: Thu Jan 5 20:53:49 PST 2023; root:xnu-8792.81.2~2/RELEASE_X86_64 x86_64
docker run --mount=type=bind,source=$(pwd),target=/repro -w /repro --platform=linux/x86_64 ruby:3.4 ./test.sh
% docker run --mount=type=bind,source=$(pwd),target=/repro -w /repro --platform=linux/x86_64 ruby:3.4 ./test.sh
Linux de42dde4ad02 6.12.10-orbstack-00297-gf8f6e015b993 #14 SMP Sun Jan 19 03:00:07 UTC 2025 x86_64 GNU/Linux
+ DEBUG=1
+ ./tailwindcss-linux-x64 -o test.css
≈ tailwindcss v4.1.4
Done in 1s
[1423.26ms] [@tailwindcss/cli] (initial build)
[ 22.20ms] ↳ Setup compiler
[1265.06ms] ↳ Scan for candidates
[ 120.37ms] ↳ Build CSS
[ 14.38ms] ↳ Write output
+ cat test.css
+ fgrep -C3 text-green-500
.text-\[rgba\(255\,255\,255\,0\.87\)\] {
color: rgba(255,255,255,0.87);
}
.text-green-500 {
color: var(--color-green-500);
}
.capitalize {docker run --mount=type=bind,source=$(pwd),target=/repro -w /repro --platform=linux/arm64 ruby:3.4 ./test.sh
Linux ec1a56cf4f26 6.12.10-orbstack-00297-gf8f6e015b993 #14 SMP Sun Jan 19 03:00:07 UTC 2025 aarch64 GNU/Linux
aarch64
+ DEBUG=1
+ ./tailwindcss-linux-arm64 -o test.css
error: Invalid Argument '-o'
Bun is a fast JavaScript runtime, package manager, bundler, and test runner. (1.2.8+adab0f64f)
Usage: bun <command> [...flags] [...args]
Commands:
run ./my-script.ts Execute a file with Bun
lint Run a package.json script
test Run unit tests with Bun
x eslint Execute a package binary (CLI), installing if needed (bunx)
repl Start a REPL session with Bun
exec Run a shell script directly with Bun
install Install dependencies for a package.json (bun i)
add lyra Add a dependency to package.json (bun a)
remove browserify Remove a dependency from package.json (bun rm)
update @remix-run/dev Update outdated dependencies
outdated Display latest versions of outdated dependencies
link [<package>] Register or link a local npm package
unlink Unregister a local npm package
publish Publish a package to the npm registry
patch <pkg> Prepare a package for patching
pm <subcommand> Additional package management utilities
build ./a.ts ./b.jsx Bundle TypeScript & JavaScript into a single file
init Start an empty Bun project from a built-in template
create vite Create a new project from a template (bun c)
upgrade Upgrade to latest version of Bun.
<command> --help Print help text for command.
Learn more about Bun: https://bun.sh/docs
Join our Discord community: https://bun.sh/discord
+ cat test.css
+ fgrep -C3 text-green-500
cat: test.css: No such file or directoryHost: MacBook 2019 (Intel) (Docker Engine)
docker run --mount=type=bind,source=$(pwd),target=/repro -w /repro --platform=linux/x86_64 ruby:3.4 ./test.sh
Linux cdb21f62c1d0 6.10.14-linuxkit #1 SMP PREEMPT_DYNAMIC Fri Nov 29 17:24:06 UTC 2024 x86_64 GNU/Linux
+ DEBUG=1
+ ./tailwindcss-linux-x64 -o test.css
≈ tailwindcss v4.1.4
Done in 1s
[1642.04ms] [@tailwindcss/cli] (initial build)
[ 36.34ms] ↳ Setup compiler
[1347.15ms] ↳ Scan for candidates
[ 181.75ms] ↳ Build CSS
[ 74.39ms] ↳ Write output
+ cat test.css
+ fgrep -C3 text-green-500
.text-\[rgba\(255\,255\,255\,0\.87\)\] {
color: rgba(255,255,255,0.87);
}
.text-green-500 {
color: var(--color-green-500);
}
.capitalize {docker run --mount=type=bind,source=$(pwd),target=/repro -w /repro --platform=linux/arm64 ruby:3.4 ./test.sh
Linux c9d9543f6df0 6.10.14-linuxkit #1 SMP PREEMPT_DYNAMIC Fri Nov 29 17:24:06 UTC 2024 aarch64 GNU/Linux
aarch64
+ DEBUG=1
+ ./tailwindcss-linux-arm64 -o test.css
≈ tailwindcss v4.1.4
Done in 22s
[22571.68ms] [@tailwindcss/cli] (initial build)
[ 924.29ms] ↳ Setup compiler
[16247.18ms] ↳ Scan for candidates
[ 5064.50ms] ↳ Build CSS
[ 270.20ms] ↳ Write output
+ cat test.css
+ fgrep -C3 text-green-500
.text-\[rgba\(255\,255\,255\,0\.87\)\] {
color: rgba(255,255,255,0.87);
}
.text-green-500 {
color: var(--color-green-500);
}
.capitalize {Hetzner CAX11 Arm64 (Docker Engine)
# uname -a
Linux ubuntu-4gb-hel1-1 6.8.0-58-generic #60-Ubuntu SMP PREEMPT_DYNAMIC Fri Mar 14 18:09:50 UTC 2025 aarch64 aarch64 aarch64 GNU/Linuxdocker run --mount=type=bind,source=$(pwd),target=/repro -w /repro --platform=linux/x86_64 ruby:3.4 ./test.sh
exec ./test.sh: exec format errordocker run --mount=type=bind,source=$(pwd),target=/repro -w /repro --platform=linux/arm64 ruby:3.4 ./test.sh
Linux 9fbea846e38e 6.8.0-58-generic #60-Ubuntu SMP PREEMPT_DYNAMIC Fri Mar 14 18:09:50 UTC 2025 aarch64 GNU/Linux
aarch64
+ DEBUG=1
+ ./tailwindcss-linux-arm64 -o test.css
≈ tailwindcss v4.1.4
Done in 3s
[3059.73ms] [@tailwindcss/cli] (initial build)
[ 32.39ms] ↳ Setup compiler
[2768.90ms] ↳ Scan for candidates
[ 208.71ms] ↳ Build CSS
[ 47.44ms] ↳ Write output
+ cat test.css
+ fgrep -C3 text-green-500
.text-\[rgba\(255\,255\,255\,0\.87\)\] {
color: rgba(255,255,255,0.87);
}
.text-green-500 {
color: var(--color-green-500);
}
.capitalize {My comment above was intended to demonstrate how to simplify a reproduction of this kind of problem without rails or ruby. Can someone who is having this problem on their dev machine please use this framework to reproduce what's happening?
@flavorjones ran the script on:
- MacOS 15.4.1
- M1 Max
- Docker version 28.0.4, build b8034c0
chmod +x ./runme.sh && ./runme.sh
./runme.sh: line 1: !/usr/bin/env: No such file or directory
Unable to find image 'ruby:3.4' locally
3.4: Pulling from library/ruby
cf05a52c0235: Pull complete
63964a8518f5: Pull complete
ca513cad200b: Pull complete
c187b51b626e: Pull complete
87ec079bfaf8: Pull complete
6d417cde9601: Pull complete
ce4f81987fcc: Pull complete
Digest: sha256:6adb999a22072227ba4ddfce8746959deb3a14bc9e32ad55e9723f5b3995aa94
Status: Downloaded newer image for ruby:3.4
Linux 952c30d78b6c 6.10.14-linuxkit #1 SMP Thu Mar 20 16:32:56 UTC 2025 x86_64 GNU/Linux
+ DEBUG=1
+ ./tailwindcss-linux-x64 -o test.css
≈ tailwindcss v4.1.4
Done in 1s
[1555.00ms] [@tailwindcss/cli] (initial build)
[ 96.00ms] ↳ Setup compiler
[ 921.00ms] ↳ Scan for candidates
[ 418.00ms] ↳ Build CSS
[ 101.00ms] ↳ Write output
+ fgrep -C3 text-green-500
+ cat test.css
.text-\[rgba\(255\,255\,255\,0\.87\)\] {
color: rgba(255,255,255,0.87);
}
.text-green-500 {
color: var(--color-green-500);
}
.capitalize {
Unable to find image 'ruby:3.4' locally
3.4: Pulling from library/ruby
de07ba6f486e: Pull complete
84649bff67ea: Pull complete
48a2a14f59a0: Pull complete
0d41c7623f41: Pull complete
bdad7cb423a1: Pull complete
78b2a9eea636: Pull complete
faea2d51befa: Pull complete
Digest: sha256:6adb999a22072227ba4ddfce8746959deb3a14bc9e32ad55e9723f5b3995aa94
Status: Downloaded newer image for ruby:3.4
Linux a9a339b0e146 6.10.14-linuxkit #1 SMP Thu Mar 20 16:32:56 UTC 2025 aarch64 GNU/Linux
aarch64
+ DEBUG=1
+ ./tailwindcss-linux-arm64 -o test.css
≈ tailwindcss v4.1.4
Done in 933ms
[934.52ms] [@tailwindcss/cli] (initial build)
[ 12.64ms] ↳ Setup compiler
[830.92ms] ↳ Scan for candidates
[ 76.42ms] ↳ Build CSS
[ 12.78ms] ↳ Write output
+ cat test.css
+ fgrep -C3 text-green-500
.text-\[rgba\(255\,255\,255\,0\.87\)\] {
color: rgba(255,255,255,0.87);
}
.text-green-500 {
color: var(--color-green-500);
}
.capitalize {
I'm not sure if this validates what you're thinking, but I am also facing a similar issue in the tailwindrails discussion rails/tailwindcss-rails#499.
Dev on m1 mac, deployment to ubuntu host via kamal.
@drwl Just to make sure I understand: it looks like you have not reproduced the problem, given the output. The color "--color-green-500" appears in both outputs.
I believe I had the same issue and documented a fix involving Kamal's remote builder.
@flavorjones text-green-500 is compiled correctly, but not py-2.
I changed your test script to: cat test.css | fgrep -C3 py-2 and here are the results (M1 Max + Docker.desktop)
$ docker run --mount=type=bind,source=$(pwd),target=/repro -w /repro --platform=linux/x86_64 ruby:3.4 ./test.sh
Unable to find image 'ruby:3.4' locally
3.4: Pulling from library/ruby
Digest: sha256:6adb999a22072227ba4ddfce8746959deb3a14bc9e32ad55e9723f5b3995aa94
Status: Downloaded newer image for ruby:3.4
Linux e9d6fdbed890 6.10.14-linuxkit #1 SMP Tue Apr 15 16:00:54 UTC 2025 x86_64 GNU/Linux
+ DEBUG=1
+ ./tailwindcss-linux-x64 -o test.css
≈ tailwindcss v4.1.4
Done in 1s
[1788.00ms] [@tailwindcss/cli] (initial build)
[ 94.00ms] ↳ Setup compiler
[1227.00ms] ↳ Scan for candidates
[ 385.00ms] ↳ Build CSS
[ 73.00ms] ↳ Write output
+ cat test.css
+ fgrep -C3 py-2
$ docker run --mount=type=bind,source=$(pwd),target=/repro -w /repro --platform=linux/arm64 ruby:3.4 ./test.sh
Unable to find image 'ruby:3.4' locally
3.4: Pulling from library/ruby
Digest: sha256:6adb999a22072227ba4ddfce8746959deb3a14bc9e32ad55e9723f5b3995aa94
Status: Downloaded newer image for ruby:3.4
Linux b2c74d120d61 6.10.14-linuxkit #1 SMP Tue Apr 15 16:00:54 UTC 2025 aarch64 GNU/Linux
aarch64
+ DEBUG=1
+ ./tailwindcss-linux-arm64 -o test.css
≈ tailwindcss v4.1.4
Done in 813ms
[814.48ms] [@tailwindcss/cli] (initial build)
[ 14.22ms] ↳ Setup compiler
[707.47ms] ↳ Scan for candidates
[ 77.00ms] ↳ Build CSS
[ 14.27ms] ↳ Write output
+ cat test.css
+ fgrep -C3 py-2
.py-1\.5 {
padding-block: calc(var(--spacing) * 1.5);
}
.py-2 {
padding-block: calc(var(--spacing) * 2);
}
.py-\[0\.2rem\] {I believe I had the same issue and documented a fix involving Kamal's remote builder.
I can confirm the problem when cross-platform-building on a Mac (docker build --platform linux/aarch64,linux/x86_64).
I also would like to point out that it's there's no fix if you're building the docker image locally on your M* Mac (arm) and deploying to AWS ECS (x86) - so basically the other way around than the issue creator described.
Only "fix" is to use x86 machines on AWS to build the image. 😕
Clearly there's something broken here.
@philipp-spiess To try to separate out the signal from the noise in this issue, @n-studio appears to have a reproduction that demonstrates something going wrong.
HI,
Dockerfile
ARG RUBY_VERSION=3.2.2
ARG NODE_MAJOR=20 # Or whatever version is used
FROM ruby:$RUBY_VERSION-slim-bookworm # Example base image
Docker buildx sets these arguments automatically for cross-platform builds
ARG TARGETPLATFORM # e.g., linux/arm64
ARG BUILDPLATFORM # e.g., linux/amd64
1. Install dependencies (OS packages, Node.js, Yarn/npm)
Crucially, if Node.js is installed manually, it must be the ARM64 version
if TARGETPLATFORM is linux/arm64. Base images might handle this.
RUN apt-get update -qq && apt-get install -y --no-install-recommends
build-essential
# ... other dependencies ...
curl
&& apt-get clean
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
Install Node.js (example, actual method might vary)
This step needs to be aware of TARGETPLATFORM if not using a multi-arch Node source
RUN curl -fsSL https://deb.nodesource.com/setup_${NODE_MAJOR}.x | bash -
&& apt-get install -y nodejs
2. Set up Rails app
WORKDIR /app
COPY Gemfile Gemfile.lock ./
RUN bundle install --jobs $(nproc) --retry 3 # Installs Rails, tailwindcss-rails, etc.
COPY package.json yarn.lock ./ # Or package-lock.json
RUN yarn install # Or npm install
COPY . .
3. Precompile assets (THIS IS WHERE TAILWIND CSS IS BUILT)
When docker buildx build --platform linux/arm64 ... is run,
this command executes within an emulated ARM64 environment on the Intel host.
The tailwindcss-rails gem will be invoked here.
RUN bundle exec rails assets:precompile
4. Configure container
EXPOSE 3000
CMD ["bundle", "exec", "rails", "server", "-b", "0.0.0.0"]
Inside the tailwindcss-rails gem (conceptual)
module Tailwindcss
class Installer
def architecture
# This detection is KEY.
# It needs to correctly identify arm64 or aarch64
# when running inside the Docker build for TARGETPLATFORM=linux/arm64.
# If it relies on Gem::Platform.local.cpu or similar, it might get the
# HOST architecture (intel) instead of the TARGET (arm64) in an emulated environment.
case Gem::Platform.local.cpu
when /x86_64|amd64/i then "x64"
when /arm64|aarch64/i then "arm64"
# ... other platforms
else
raise "Unsupported architecture: #{Gem::Platform.local.cpu}"
end
end
def platform_os
# Detect OS (e.g., "linux", "darwin")
Gem::Platform.local.os.downcase
end
def download_and_install_binary
arch = architecture() # e.g., "x64" or "arm64"
os = platform_os() # e.g., "linux"
version = "v4.1.3" # From gem's dependency or configuration
# Constructs URL like: tailwindcss-linux-arm64
binary_name = "tailwindcss-#{os}-#{arch}"
url = "https://github.com/tailwindlabs/tailwindcss/releases/download/#{version}/#{binary_name}"
# ... code to download from URL, save to a known location, and make executable ...
end
end
When rails assets:precompile or rails tailwindcss:build runs:
1. An instance of Installer (or similar) ensures the binary is present.
2. The gem executes the downloaded binary:
./path/to/downloaded/tailwindcss-linux-arm64 -i ./app/assets/stylesheets/application.tailwind.css -o ./app/assets/builds/application.css --minify
If this binary is the x64 version running in an ARM64 emulated env, it will fail silently or error out.
end
Good luck!
SUMAN SUHAG
@n-studio Hey! Do you mind running your repro again with the new improved debugging feature in 4.1.6? All you need to do is to set the DEBUG env var to * and we'll create a log file that will include infos about the current file system setup.
Updated tests
#!/usr/bin/env bash
# download binaries
wget -q -c https://github.com/tailwindlabs/tailwindcss/releases/download/v4.1.6/tailwindcss-linux-arm64
wget -q -c https://github.com/tailwindlabs/tailwindcss/releases/download/v4.1.6/tailwindcss-linux-x64
# set up target html
cat > test.html <<EOF
<html>
<h1 class="py-2 px-3 text-green-500">Hello</h1>
</html>
EOF
# set up the script we'll run in the container
cat > test.sh <<EOF
#!/usr/bin/env bash
uname -a
if uname -m | fgrep aarch64 ; then
bin=./tailwindcss-linux-arm64
else
bin=./tailwindcss-linux-x64
fi
rm -f test.css
set -x
DEBUG=* \$bin -o test.css
cat test.css | fgrep -C3 py-2
cat /repro/tailwindcss-11.log
EOF
# run tailwind in the container
chmod +x tailwindcss-linux-* test.sh
docker run --mount=type=bind,source=$(pwd),target=/repro -w /repro --platform=linux/x86_64 ruby:3.4 ./test.sh
docker run --mount=type=bind,source=$(pwd),target=/repro -w /repro --platform=linux/arm64 ruby:3.4 ./test.shResults (M1 Max + Docker.desktop):
$ docker run --mount=type=bind,source=$(pwd),target=/repro -w /repro --platform=linux/x86_64 ruby:3.4 ./test.sh
Unable to find image 'ruby:3.4' locally
3.4: Pulling from library/ruby
Digest: sha256:6adb999a22072227ba4ddfce8746959deb3a14bc9e32ad55e9723f5b3995aa94
Status: Downloaded newer image for ruby:3.4
Linux f10f3866258d 6.10.14-linuxkit #1 SMP Tue Apr 15 16:00:54 UTC 2025 x86_64 GNU/Linux
+ DEBUG='*'
+ ./tailwindcss-linux-x64 -o test.css
≈ tailwindcss v4.1.6
[DEBUG] Writing debug info to: `/repro/tailwindcss-11.log`
Done in 1s
[1492.00ms] [@tailwindcss/cli] (initial build)
[ 105.00ms] ↳ Setup compiler
[ 894.00ms] ↳ Scan for candidates
[ 391.00ms] ↳ Build CSS
[ 94.00ms] ↳ Write output
+ cat test.css
+ fgrep -C3 py-2
+ cat /repro/tailwindcss-11.log
2025-05-14T14:42:13.669737Z INFO tailwindcss_oxide::scanner: Provided sources:
2025-05-14T14:42:13.671885Z INFO tailwindcss_oxide::scanner: Source: PublicSourceEntry { base: "/repro", pattern: "**/*", negated: false }
2025-05-14T14:42:13.674531Z INFO tailwindcss_oxide::scanner: Optimized sources:
2025-05-14T14:42:13.674575Z INFO tailwindcss_oxide::scanner: Source: Auto { base: "/repro" }
2025-05-14T14:42:13.699240Z INFO scan_sources: tailwindcss_oxide::scanner: enter
2025-05-14T14:42:13.710687Z INFO scan_sources: tailwindcss_oxide::scanner: Discovering "/repro/tailwindcss-linux-x64"
2025-05-14T14:42:13.712270Z INFO scan_sources: tailwindcss_oxide::scanner: Discovering "/repro/tailwindcss-linux-arm64"
2025-05-14T14:42:13.712476Z INFO scan_sources: tailwindcss_oxide::scanner: Discovering "/repro/test.html"
2025-05-14T14:42:13.712612Z INFO scan_sources: tailwindcss_oxide::scanner: Discovering "/repro/test.sh"
2025-05-14T14:42:13.713758Z INFO scan_sources: tailwindcss_oxide::scanner: exit
2025-05-14T14:42:13.714181Z INFO extract_candidates: tailwindcss_oxide::scanner: enter
2025-05-14T14:42:13.714382Z INFO extract_candidates:read_all_files: tailwindcss_oxide::scanner: enter
2025-05-14T14:42:13.714415Z INFO extract_candidates:read_all_files: tailwindcss_oxide::scanner: Reading 4 file(s)
2025-05-14T14:42:13.733659Z INFO tailwindcss_oxide::scanner: Reading "/repro/test.html"
2025-05-14T14:42:13.733672Z INFO tailwindcss_oxide::scanner: Reading "/repro/test.sh"
2025-05-14T14:42:13.845949Z INFO tailwindcss_oxide::scanner: Reading "/repro/tailwindcss-linux-arm64"
2025-05-14T14:42:13.854892Z INFO tailwindcss_oxide::scanner: Reading "/repro/tailwindcss-linux-x64"
2025-05-14T14:42:13.900891Z INFO extract_candidates:read_all_files: tailwindcss_oxide::scanner: exit
2025-05-14T14:42:13.901360Z INFO extract_candidates:parse_all_blobs: tailwindcss_oxide::scanner: enter
2025-05-14T14:42:13.901566Z INFO extract_candidates:parse_all_blobs:extract: tailwindcss_oxide::scanner: enter
2025-05-14T14:42:14.563263Z INFO extract_candidates:parse_all_blobs:extract: tailwindcss_oxide::scanner: exit
2025-05-14T14:42:14.567904Z INFO extract_candidates:parse_all_blobs: tailwindcss_oxide::scanner: exit
2025-05-14T14:42:14.577713Z INFO extract_candidates: tailwindcss_oxide::scanner: exit
$ docker run --mount=type=bind,source=$(pwd),target=/repro -w /repro --platform=linux/arm64 ruby:3.4 ./test.sh
Unable to find image 'ruby:3.4' locally
3.4: Pulling from library/ruby
Digest: sha256:6adb999a22072227ba4ddfce8746959deb3a14bc9e32ad55e9723f5b3995aa94
Status: Downloaded newer image for ruby:3.4
Linux ac588f3a4e72 6.10.14-linuxkit #1 SMP Tue Apr 15 16:00:54 UTC 2025 aarch64 GNU/Linux
aarch64
+ DEBUG='*'
+ ./tailwindcss-linux-arm64 -o test.css
≈ tailwindcss v4.1.6
[DEBUG] Writing debug info to: `/repro/tailwindcss-11.log`
Done in 765ms
[766.33ms] [@tailwindcss/cli] (initial build)
[ 14.16ms] ↳ Setup compiler
[662.20ms] ↳ Scan for candidates
[ 75.26ms] ↳ Build CSS
[ 13.33ms] ↳ Write output
+ cat test.css
+ fgrep -C3 py-2
.py-1\.5 {
padding-block: calc(var(--spacing) * 1.5);
}
.py-2 {
padding-block: calc(var(--spacing) * 2);
}
.py-\[0\.2rem\] {
+ cat /repro/tailwindcss-11.log
2025-05-14T14:42:13.669737Z INFO tailwindcss_oxide::scanner: Provided sources:
2025-05-14T14:42:13.671885Z INFO tailwindcss_oxide::scanner: Source: PublicSourceEntry { base: "/repro", pattern: "**/*", negated: false }
2025-05-14T14:42:13.674531Z INFO tailwindcss_oxide::scanner: Optimized sources:
2025-05-14T14:42:13.674575Z INFO tailwindcss_oxide::scanner: Source: Auto { base: "/repro" }
2025-05-14T14:42:13.699240Z INFO scan_sources: tailwindcss_oxide::scanner: enter
2025-05-14T14:42:13.710687Z INFO scan_sources: tailwindcss_oxide::scanner: Discovering "/repro/tailwindcss-linux-x64"
2025-05-14T14:42:13.712270Z INFO scan_sources: tailwindcss_oxide::scanner: Discovering "/repro/tailwindcss-linux-arm64"
2025-05-14T14:42:13.712476Z INFO scan_sources: tailwindcss_oxide::scanner: Discovering "/repro/test.html"
2025-05-14T14:42:13.712612Z INFO scan_sources: tailwindcss_oxide::scanner: Discovering "/repro/test.sh"
2025-05-14T14:42:13.713758Z INFO scan_sources: tailwindcss_oxide::scanner: exit
2025-05-14T14:42:13.714181Z INFO extract_candidates: tailwindcss_oxide::scanner: enter
2025-05-14T14:42:13.714382Z INFO extract_candidates:read_all_files: tailwindcss_oxide::scanner: enter
2025-05-14T14:42:13.714415Z INFO extract_candidates:read_all_files: tailwindcss_oxide::scanner: Reading 4 file(s)
2025-05-14T14:42:13.733659Z INFO tailwindcss_oxide::scanner: Reading "/repro/test.html"
2025-05-14T14:42:13.733672Z INFO tailwindcss_oxide::scanner: Reading "/repro/test.sh"
2025-05-14T14:42:13.845949Z INFO tailwindcss_oxide::scanner: Reading "/repro/tailwindcss-linux-arm64"
2025-05-14T14:42:13.854892Z INFO tailwindcss_oxide::scanner: Reading "/repro/tailwindcss-linux-x64"
2025-05-14T14:42:13.900891Z INFO extract_candidates:read_all_files: tailwindcss_oxide::scanner: exit
2025-05-14T14:42:13.901360Z INFO extract_candidates:parse_all_blobs: tailwindcss_oxide::scanner: enter
2025-05-14T14:42:13.901566Z INFO extract_candidates:parse_all_blobs:extract: tailwindcss_oxide::scanner: enter
2025-05-14T14:42:14.563263Z INFO extract_candidates:parse_all_blobs:extract: tailwindcss_oxide::scanner: exit
2025-05-14T14:42:14.567904Z INFO extract_candidates:parse_all_blobs: tailwindcss_oxide::scanner: exit
2025-05-14T14:42:14.577713Z INFO extract_candidates: tailwindcss_oxide::scanner: exit
2025-05-14T14:42:23.730497Z INFO tailwindcss_oxide::scanner: Provided sources:
2025-05-14T14:42:23.730679Z INFO tailwindcss_oxide::scanner: Source: PublicSourceEntry { base: "/repro", pattern: "**/*", negated: false }
2025-05-14T14:42:23.730775Z INFO tailwindcss_oxide::scanner: Optimized sources:
2025-05-14T14:42:23.730868Z INFO tailwindcss_oxide::scanner: Source: Auto { base: "/repro" }
2025-05-14T14:42:23.732274Z INFO scan_sources: tailwindcss_oxide::scanner: enter
2025-05-14T14:42:23.732786Z INFO scan_sources: tailwindcss_oxide::scanner: Discovering "/repro/tailwindcss-linux-x64"
2025-05-14T14:42:23.732896Z INFO scan_sources: tailwindcss_oxide::scanner: Discovering "/repro/tailwindcss-linux-arm64"
2025-05-14T14:42:23.732992Z INFO scan_sources: tailwindcss_oxide::scanner: Discovering "/repro/test.html"
2025-05-14T14:42:23.733031Z INFO scan_sources: tailwindcss_oxide::scanner: Discovering "/repro/test.sh"
2025-05-14T14:42:23.733124Z INFO scan_sources: tailwindcss_oxide::scanner: exit
2025-05-14T14:42:23.733161Z INFO extract_candidates: tailwindcss_oxide::scanner: enter
2025-05-14T14:42:23.733195Z INFO extract_candidates:read_all_files: tailwindcss_oxide::scanner: enter
2025-05-14T14:42:23.733226Z INFO extract_candidates:read_all_files: tailwindcss_oxide::scanner: Reading 4 file(s)
2025-05-14T14:42:23.735233Z INFO tailwindcss_oxide::scanner: Reading "/repro/test.sh"
2025-05-14T14:42:23.735229Z INFO tailwindcss_oxide::scanner: Reading "/repro/test.html"
2025-05-14T14:42:23.828151Z INFO tailwindcss_oxide::scanner: Reading "/repro/tailwindcss-linux-arm64"
2025-05-14T14:42:23.835786Z INFO tailwindcss_oxide::scanner: Reading "/repro/tailwindcss-linux-x64"
2025-05-14T14:42:23.886267Z INFO extract_candidates:read_all_files: tailwindcss_oxide::scanner: exit
2025-05-14T14:42:23.886457Z INFO extract_candidates:parse_all_blobs: tailwindcss_oxide::scanner: enter
2025-05-14T14:42:23.886492Z INFO extract_candidates:parse_all_blobs:extract: tailwindcss_oxide::scanner: enter
2025-05-14T14:42:24.369626Z INFO extract_candidates:parse_all_blobs:extract: tailwindcss_oxide::scanner: exit
2025-05-14T14:42:24.374728Z INFO extract_candidates:parse_all_blobs: tailwindcss_oxide::scanner: exit
2025-05-14T14:42:24.383917Z INFO extract_candidates: tailwindcss_oxide::scanner: exit@n-studio Thanks! And very bizarre. What version of macOS and Docker do you have? I wonder if it has to be some specific versions that trigger that. The same issue does not repro on:
- M4 Max
- macOS 15.4.1
- Docker Desktop 4.37.2
We were able to reproduce this on @RobinMalfait's machine who had mostly the same versions as me, the only difference is that he is on the M1 Max. Lol
- M1 Max
- macOS 15.4.1
- Docker Desktop 4.41.2
Hey!
So we did a bunch of testing and figured out the bug, or at least how to give you a workaround. More in depth information here: oven-sh/bun#19677
Turns out that:
- If you are on an M1
- Using Docker
- With
Apple Virtualization framework- With the
Use Rosetta for x86_64/amd64 emulation on Apple Siliconoption checked
- With the
- Running a Docker file with
--platform=linux/x86_64
If you then have values such as 0.25 or 1.25, then they all get truncated to just 0 and 1 respectively.
I don't think there is anything we can do to solve this issue unfortunately.
However, if you go into your Docker settings under the Virtual Machine Options settings, then you can either:
- Uncheck the
Use Rosetta for x86_64/amd64 emulation on Apple Siliconoption - Switch to QEMU (Legacy)
- Switch to Docker VMM
How this bug relates to Tailwind CSS itself:
One of the checks we do internally when you use px-4, is that we check if the value 4 is a valid multiplier of 0.25 because we don't want to support px-4.123 for example. The 0.25 gets turned into 0 so our check doing 4 % 0.25 === 0 now becomes 4 % 0 === 0 instead. 4 % 0.25 correctly produces 0, but 4 % 0 produces NaN which is not 0 of course and therefore the px-4 is ignored because we consider it invalid.
This is also why other classes did work like a bg-red-500 or flex because they are not dealing with numbers.
Hopefully any of these workarounds will work for you.
This morning I updated my M1 to macOS 15.5 (24F74) and that also seems to fix the problem. Since there are enough workarounds right now, and since we can't do anything about this bug I'm going to close it for now.
So in summary, if you run into this bug, make sure to:
- Update your M1 to the latest macOS version
- Use one of the workarounds as described above by changing the Docker desktop settings
Hope this helps!
(What a roller coaster of a bug 😅)
Thanks for the detailed write up with workarounds! Totally insane bug 🎢🐛
I encountered this this morning on 15.5, but the above fixed it for me
I did run into the same issue today.
Macbook Air M2 running 15.6.1 and docker 4.44.3
the workaround rails/tailwindcss-rails#553 (comment) "fixed" it for me too.
If anybody searches for the workaround for podman (without desktop)
cat > $HOME/.config/containers/containers.conf << EOF
[machine]
rosetta=false
EOF
podman machine rm -f
podman machine init
you see the rosetta status with: podman machine inspect | jq ".[0].Rosetta", it has to be false