Skip to main content
Pylon’s SSR bundler automatically compiles Tailwind v4 if it finds app/globals.css. The output ships as a content-hashed <link rel="stylesheet">, injected directly into <head>. There is no flash of unstyled content (FOUC), no Tailwind Play CDN script, and no separate build step.

Setup

Create app/globals.css:
pylon dev picks up the file on the next bundle and emits /_pylon/build/styles-<hash>.css. The SSR runtime adds <link rel="stylesheet"> to every page’s <head>. You do not need a tailwind.config.js. Tailwind v4 uses CSS-first configuration. Theme tokens go in the @theme block:
bg-brand, text-brand, and font-sans are now available throughout your app.

How the head injection works

Tailwind in SSR has a timing problem: your root layout renders the <head> before the SSR runtime knows which CSS file to include. Pylon solves it by rewriting React’s HTML output as it streams.
  1. The bundler compiles app/globals.css into styles-<hash>.css in the build output.
  2. On render, the SSR runtime reads the manifest to find the hash.
  3. As React’s HTML stream flows past, the runtime watches for </head> (with a small carry buffer to handle chunk-boundary splits) and splices in <link rel="stylesheet" href="/_pylon/build/styles-<hash>.css"> before the close tag.
  4. The browser starts fetching the CSS while it is still parsing the body. There is no FOUC and no extra round trip.
Your RootLayout does not need to know anything about it. Write the head you want. Pylon adds the right links.

Class scanning

Tailwind v4 scans your source files for class names at build time. The @source directive in globals.css controls which files it scans:
Without @source, Tailwind’s auto-discovery walks package.json dependencies and likely-looking source folders. Adding the directive is more explicit, and it survives unusual layouts.

Hot rebuild

pylon dev rebuilds the bundle (and the Tailwind CSS) when you save a source file. Refresh the browser to see styles update. Hot reload without a page refresh for CSS is on the roadmap.

Production

The flow is the same. pylon (the production binary) compiles Tailwind at boot. The output is fingerprinted, so CDNs and browsers cache it indefinitely. Editing globals.css produces a new hash, which breaks the cache automatically. There is no separate build step. The single binary handles development and production identically.

Other CSS

Tailwind is the recommended path because it is wired into the bundler. For other CSS, such as vanilla CSS, a different framework, or CSS-in-JS, you have two options: Stylesheet in web/dist/: drop a styles.css next to your other static assets and link to it from your root layout:
The frontend directory serves it directly, with no bundler involvement and no fingerprinting. Per-component styles: for component-scoped CSS, such as CSS modules or styled-components, apply it the same way you would in any React app. The SSR runtime renders whatever React renders. If you want CSS modules or PostCSS plugins wired into the bundler, file an issue. The implementation lives in packages/functions/src/ssr-client-bundler.ts, and we are glad to extend it.