From Tailwind CDN to Production: Generate an Optimised CSS Bundle

The Tailwind CDN is a fantastic tool for rapid prototyping. Drop a single script tag into your HTML and you have access to every Tailwind utility class immediately - no build step, no configuration, no hanging around. It's perfect for quickly putting together a basic game, single-serving page, or letting an AI agent iterate on a design without friction.

<script src="https://cdn.tailwindcss.com"></script>

It works by scanning your markup for Tailwind classes, then generates a CSS bundle to support those classes, which is then inserted automatically into your site. Great!

But when it's time to deploy, that CDN script needs to be taken out.

Why? Because that JIT compilation happens entirely in your user's browser. It forces the device to download a large javascript file and burn CPU cycles compiling CSS that could have been static. On production sites, we want to avoid that performance hit and serve a tiny, cacheable CSS file instead.

Uh oh! Better not use this in production..

Uh oh! Better not use this in production..

The Fix: Tailwind CLI

Tailwind provides a standalone CLI that scans your HTML, identifies which classes you're using, and generates a CSS file containing only those styles. The good news is that now we're using Tailwind v4, we can do this as lightly and quickly with a single binary, and minimal config bootstrapping.

Step 1: Install the CLI

We'll install the core package and the new CLI tool via npm:

npm install tailwindcss @tailwindcss/cli

Step 2: Create an Input CSS File

Create a file called input.css. In Tailwind v4, we no longer use the @tailwind directives. Instead, we use a single standard CSS import:

@import "tailwindcss";

With Tailwind v3, we would have had to create a tailwind.config.js and specify multiple layers. However with v4, we get away with the simpler input.css above, and no need for a config file.

Step 3: Generate the Production CSS

Run the CLI using the npx command:

npx @tailwindcss/cli -i input.css -o styles.css --minify --content "./**/*.html"

This scans your HTML files, finds every Tailwind class you're using, and generates a CSS file which contains those styles, rather than the full set of Tailwind utilities.

Step 4: Understanding the Output

When looking at that generated file, you might notice some code in there which doesn't appear on your page, e.g.

a {
  color: inherit;
  -webkit-text-decoration: inherit;
  text-decoration: inherit;
}
b, strong {
  font-weight: bolder;
}

These aren't in our markup, so what gives? This is Tailwind's base reset, known as Preflight.

In modern Tailwind (v3 and v4), "purging" is automatic and aggressive. The engine literally does not generate a utility class (like .bg-red-500) unless it sees it in your files.

However, it does include a block of base styles (about 3-4KB) by default. Its job is to ensure your site looks exactly the same on Chrome, Firefox, and Safari. This reset involves stripping browser-specific defaults around things like buttons, or box-sizing and default header margins which complicate responsive size calculations.

If you are building a tiny widget, an email template, or embedding into an existing site where you don't want Tailwind to reset global styles, you can disable Preflight by making your imports more granular in input.css:

/* 1. Import the theme variables (colors, fonts, etc.) */
@import "tailwindcss/theme";

/* 2. Import ONLY the utilities (the classes you actually use) */
@import "tailwindcss/utilities";

/* Not Included: @import "tailwindcss/preflight"; */

For most sites, however, it's safest to keep the default @import "tailwindcss"; to ensure your layout behaves consistently.

Step 5: Update Your HTML

Replace the CDN script with a link to your generated CSS:

<!-- Remove this -->
<script src="https://cdn.tailwindcss.com"></script>

<!-- Add this -->
<link href="styles.css" rel="stylesheet">

The Size Difference

For a typical single-page site or simple game, the results are dramatic:

ApproachSize
Tailwind CDN~140KB (JS)
Generated CSS (typical)5-15KB
Generated CSS (minimal page)2-5KB

That's a significant reduction, and it's plain CSS - no javascript required, fully cacheable, renders immediately.

Watch Mode for Development

While developing, you (or your AI assistant..) will likely be constantly tweaking the markup until it looks "just right". If you want to keep iterating without the CDN, run the CLI in watch mode:

npx @tailwindcss/cli -i input.css -o styles.css --minify --content "./**/*.html" --watch

It'll rebuild automatically whenever you save changes to your HTML files.

Incremental vs fresh builds

If you are running the --watch option, you may notice an odd pattern. You have a class in your markup (text-blue-500), it appears in your styles.css, all good. Then you edit it to text-blue-600, save, styles.css updates and your page looks good. However, styles.css now contains both text-blue-500 and text-blue-600. Why is this?

The Tailwind CLI optimises for speed. Whenever an update happens, it is checking for new additions (text-blue-600) and adding them to the compiled styles.css file. To safely remove text-blue-500, it would need to scan all files to see if it was still in use or not, and then get rid of it. Doable, but a lot slower. This means that while you're in --watch mode, the CSS file won't be quite production-ready. This mode is good for rapid development, but before you go to production, kill that process, and re-run it without the --watch flag:

npx @tailwindcss/cli -i input.css -o styles.css --minify --content "./**/*.html"

This will rebuild the styles.css, containing the smallest possible Tailwind output.

A Complete Example

Here's a minimal project structure:

my-site/
├── index.html
├── input.css
└── styles.css (generated)

index.html:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>My Site</title>
  <link href="styles.css" rel="stylesheet">
</head>
<body class="bg-gray-100 min-h-screen flex items-center justify-center">
  <div class="bg-white p-8 rounded-lg shadow-lg max-w-md">
    <h1 class="text-2xl font-bold text-gray-900 mb-4">Hello, World</h1>
    <p class="text-gray-600">This page uses only the Tailwind classes it needs.</p>
  </div>
</body>
</html>

Run the build:

npx @tailwindcss/cli -i input.css -o styles.css --minify --watch

The generated styles.css will contain only the styles for bg-gray-100, min-h-screen, flex, items-center, justify-center, bg-white, p-8, rounded-lg, shadow-lg, max-w-md, text-2xl, font-bold, text-gray-900, mb-4, and text-gray-600, and nothing more.

Wrapping Up

The Tailwind CDN is excellent for development - zero friction, instant feedback. But for production, take the extra minute to generate an optimised bundle. Your users get a faster page load, you avoid javascript dependencies for styling, and you're shipping kilobytes instead of hundreds of kilobytes.

The Tailwind CLI makes this trivially easy, especially for simple single-file sites without need for a build system.


PHP UK Conference, London 2026

IPC Berlin Speaker

In February 2026, I'll be speaking at the PHP UK Conference in London. I'll be telling the story behind EverythingIsShowbiz.com, a site that went from a vibe-coded side project, to a useful experiment in integration of AI into PHP workflows.

Get your ticket now and I'll see you there!

Share This Article

Related Articles


More