In astro’s server output mode, prerendered pages and server-rendered pages are built by two separate environments. Each one bundles your shared layout independently, so the same stylesheet comes out twice under different hashed names, and both land in dist/client/_astro/. Every visitor to the dynamic pages downloads css they may already have from the static ones.
That is astro issue #17298. The obvious fix is content hashing, and it does not work here.
why content hashing fails
If both environments produce the same bytes, naming assets by content hash collapses them for free. An earlier exploration did exactly that, and it worked, briefly.
Then the two files stopped being identical. With tailwind v4, @tailwindcss/vite scans each environment’s module graph for utility candidates. The SSR environment’s graph includes astro’s bundled server runtime and the node adapter, and tailwind’s scanner picks candidate strings out of that javascript. I traced .underline and .italic to strings inside astro’s own server runtime, and .relative, .container, and .lowercase to the adapter.
So the SSR copy of your stylesheet contains utility classes that exist because the bundler’s output happened to contain those words. The two files are 95% the same and hash differently.
keying by source modules
The fix I sent keys deduplication on module identity instead of content: the prerender build records which set of css source modules produced each emitted asset, and the SSR build renames its own asset to the prerender filename when it is backed by the exact same set. The divergent utilities are scanner false positives from bundled js. Every real class comes from source files both environments scan identically.
One rolldown gotcha from the implementation: in generateBundle, the bundle object is a proxy that silently ignores direct key assignment. bundle[newName] = asset leaves bundle[newName] undefined, no error. Mutating asset.fileName in place is what actually re-keys it, and then the manifest and asset tracking stay consistent without further changes.
The test fixture asserts one css file is emitted and that both the prerendered html and the server-rendered response link that same file. On main it fails with two.
The PR is withastro/astro#17488. It was merged into main on 25 july 2026. The last release at the time of writing is astro 7.1.3, so the fix is waiting on the next patch.