The Problem
You want to use Tailwind CSS in your ASP.NET Core application, but the standard setup requires Node.js, npm, a package.json, a tailwind.config.js, and a build pipeline that runs npx tailwindcss before every deploy. That's an entire JavaScript toolchain bolted onto a C# project — just to generate CSS.
Your CI/CD pipeline now needs Node.js installed alongside the .NET SDK. Your Docker images grow larger. New team members need to run npm install before they can style a page. And if you're building a Blazor app, the disconnect between the .NET build and the Node.js build is even more jarring.
You need Tailwind CSS without the JavaScript baggage — something that integrates natively into the .NET build pipeline, auto-downloads the right binary, watches your files during development, and compiles optimized CSS at publish time. Zero npm. Zero config files. Zero Node.js.
Ingredients
Noundry.Tailbreeze
vlatest
Runtime library with middleware, tag helpers, and Tailwind CLI management
Noundry.Tailbreeze.Build
vlatest
MSBuild tasks for compile-time CSS generation during dotnet publish
.NET 10 SDK
v10.0
Target framework for the application
Tailbreeze comes in two complementary packages. The runtime package handles development-time watching and CSS serving, while the build package adds MSBuild integration for publish-time compilation.
Preparation
dotnet add package Noundry.Tailbreeze
dotnet add package Noundry.Tailbreeze.Build
The runtime package (Noundry.Tailbreeze) provides the middleware and tag helpers for serving compiled CSS. The build package (Noundry.Tailbreeze.Build) adds MSBuild targets that automatically compile your CSS during dotnet publish.
2. Understand what happens behind the scenes
When your application starts for the first time, Tailbreeze:
- Downloads the official Tailwind CSS standalone CLI binary from GitHub releases (no Node.js needed)
- Caches it locally at
%LOCALAPPDATA%/Tailbreeze/cli/{version}/— downloaded once, reused forever - Scans your
.cshtml,.razor, and.htmlfiles for Tailwind utility classes - Compiles a CSS file containing only the classes you actually use
- Watches for file changes in development mode and recompiles automatically
At publish time, the Build package runs the CLI with the --minify flag, producing an optimized CSS file baked into your publish output.
3. Create your input CSS file (optional)
If you want to add custom styles or use Tailwind's @apply directive, create wwwroot/css/app.css:
@tailwind base;
@tailwind components;
@tailwind utilities;
/* Your custom styles here */
.glass {
@apply bg-white/10 backdrop-blur-md border border-white/20 rounded-xl;
}
If you skip this step, Tailbreeze uses a sensible default input file automatically.
The Code
The setup is remarkably simple — two lines in Program.cs and one tag helper in your layout. Let's walk through a complete Razor Pages application with Tailwind CSS.
using Tailbreeze.Extensions;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
// Add Tailbreeze — this registers the CLI manager, file watcher,
// and CSS compilation service. No configuration needed.
builder.Services.AddTailbreeze();
var app = builder.Build();
app.UseStaticFiles();
// Serve the compiled Tailwind CSS at /tailbreeze/app.css
// In development, this also starts the file watcher for hot reload.
app.UseTailbreeze();
app.MapRazorPages();
app.Run();
@using MyApp
@namespace MyApp.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, Tailbreeze
<!DOCTYPE html>
<html lang="en" class="dark">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - MyApp</title>
<!-- Tailbreeze tag helper — renders the compiled CSS link -->
<tailwind-link />
</head>
<body class="bg-zinc-950 text-zinc-100 min-h-screen">
<nav class="border-b border-zinc-800 px-6 py-4">
<div class="max-w-6xl mx-auto flex items-center justify-between">
<a href="/" class="text-xl font-bold bg-gradient-to-r from-amber-400 to-orange-500 bg-clip-text text-transparent">
MyApp
</a>
<div class="flex gap-4">
<a href="/" class="text-zinc-400 hover:text-white transition-colors">Home</a>
<a href="/about" class="text-zinc-400 hover:text-white transition-colors">About</a>
</div>
</div>
</nav>
<main class="max-w-6xl mx-auto px-6 py-12">
@RenderBody()
</main>
<footer class="border-t border-zinc-800 px-6 py-8 text-center text-zinc-500 text-sm">
© @DateTime.UtcNow.Year MyApp. Built with .NET and Tailwind CSS.
</footer>
</body>
</html>
@page
@model IndexModel
@{ ViewData["Title"] = "Home"; }
<div class="space-y-12">
<!-- Hero Section -->
<section class="text-center py-16">
<h1 class="text-5xl font-bold mb-4">
Welcome to
<span class="bg-gradient-to-r from-amber-400 to-orange-500 bg-clip-text text-transparent">
MyApp
</span>
</h1>
<p class="text-xl text-zinc-400 max-w-2xl mx-auto">
Built with ASP.NET Core and Tailwind CSS — no Node.js required.
</p>
</section>
<!-- Feature Cards -->
<div class="grid md:grid-cols-3 gap-6">
<div class="bg-white/5 backdrop-blur-md border border-white/10 rounded-xl p-6 hover:border-amber-500/50 transition-colors">
<div class="text-3xl mb-3">⚡</div>
<h3 class="text-lg font-semibold mb-2">Zero Config</h3>
<p class="text-zinc-400 text-sm">
Two lines of C# and you have Tailwind CSS. No npm, no config files, no build scripts.
</p>
</div>
<div class="bg-white/5 backdrop-blur-md border border-white/10 rounded-xl p-6 hover:border-amber-500/50 transition-colors">
<div class="text-3xl mb-3">🔥</div>
<h3 class="text-lg font-semibold mb-2">Hot Reload</h3>
<p class="text-zinc-400 text-sm">
Edit a Razor page, save, and see your styles update instantly. The file watcher runs automatically in development.
</p>
</div>
<div class="bg-white/5 backdrop-blur-md border border-white/10 rounded-xl p-6 hover:border-amber-500/50 transition-colors">
<div class="text-3xl mb-3">📦</div>
<h3 class="text-lg font-semibold mb-2">Optimized Builds</h3>
<p class="text-zinc-400 text-sm">
Production CSS is automatically minified and tree-shaken during dotnet publish. Only the classes you use ship.
</p>
</div>
</div>
</div>
Advanced Configuration
Tailbreeze works with zero configuration, but you can customize every aspect when needed. Here's how to control the Tailwind version, compilation mode, input/output paths, and more.
using Tailbreeze.Extensions;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
// Advanced Tailbreeze configuration
builder.Services.AddTailbreeze(options =>
{
// Pin a specific Tailwind CSS version (default: latest v4)
options.Version = "4.0.0";
// Custom input CSS file path (default: auto-generated)
options.InputPath = "wwwroot/css/app.css";
// Custom output CSS file path (default: wwwroot/tailbreeze/app.css)
options.OutputPath = "wwwroot/css/output.css";
// Enable minification in all environments (default: only in production)
options.Minify = true;
// Disable hot reload file watching (default: enabled in Development)
options.HotReload = false;
// Compilation mode:
// Full — Download CLI, compile locally (default)
// Cdn — Use Tailwind Play CDN (development only)
// Optimized — Full compilation with aggressive tree-shaking
options.Mode = TailbreezeMode.Full;
});
var app = builder.Build();
app.UseStaticFiles();
app.UseTailbreeze();
app.MapRazorPages();
app.Run();
# Multi-stage build — Tailbreeze compiles CSS during 'dotnet publish'
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
COPY *.csproj ./
RUN dotnet restore
COPY . .
# The Noundry.Tailbreeze.Build MSBuild target runs automatically here,
# downloading the Tailwind CLI and compiling optimized, minified CSS.
RUN dotnet publish -c Release -o /app/publish --no-restore
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime
WORKDIR /app
# Tailbreeze needs a writable directory for the CLI binary cache
RUN mkdir -p /app/Tailbreeze && chown app:app /app/Tailbreeze
COPY --from=build /app/publish .
USER app
EXPOSE 8080
ENTRYPOINT ["dotnet", "MyApp.dll"]
Plating
You now have Tailwind CSS fully integrated into your ASP.NET Core application — without a single line of JavaScript, without package.json, and without Node.js anywhere in your stack.
Here's what Tailbreeze gives you:
- Two-line setup —
AddTailbreeze()andUseTailbreeze()is all you need - Automatic CLI management — The Tailwind standalone binary is downloaded once and cached locally
- Hot reload in development — Edit a
.cshtmlfile, save, and your CSS updates instantly - Optimized production builds — MSBuild integration compiles and minifies CSS during
dotnet publish - No Node.js dependency — Your CI/CD pipeline only needs the .NET SDK
- Tailwind v4 support — Ships with the latest Tailwind CSS by default, configurable to any version
- Works everywhere — Razor Pages, MVC, Blazor Server, and Blazor WebAssembly
The <tailwind-link /> tag helper generates the correct <link> element pointing to your compiled CSS, handling cache-busting automatically in production.
Docker-friendly: The Noundry.Tailbreeze.Build package runs as an MSBuild target during dotnet publish, so your multi-stage Docker builds just work — no separate Node.js build step needed.
Next steps:
- Add custom Tailwind plugins via your
app.cssinput file - Use
@applydirectives to create reusable component classes - Explore the
TailbreezeMode.Cdnoption for rapid prototyping without downloading the CLI - Combine with Alpine.js for interactive components without a JavaScript build step
Tailbreeze proves that modern CSS tooling doesn't require a JavaScript ecosystem. Your .NET app, your .NET build, your .NET deploy — with world-class CSS utility classes.
Was this recipe helpful?
Chef George
.NET Architect & Head Chef
25+ years crafting enterprise C# solutions. Creator of the Noundry platform. Passionate about clean architecture, cloud-agnostic deployments, and code that cooks.