Building Modern Web Apps with Next.js 15
A deep dive into Next.js 15's App Router, React Server Components, and how they change the way we build for the web.
Read the articleExploring Tailwind CSS v4's new engine, CSS-first configuration, and how it improves the developer experience for modern web projects.

Tailwind CSS v4 introduces a redesigned build engine and CSS-first configuration. Build performance depends on the project, integrations, and cache state; measure those conditions in your own repository before assigning a speedup to an upgrade.
But speed is just the beginning. The real story of v4 is a philosophical shift: CSS-first configuration.
In v4, you can define design tokens directly in CSS using @theme. JavaScript configuration is still supported for compatibility when explicitly loaded with @config:
@import 'tailwindcss';
@theme {
--color-bg-primary: #0d1117;
--color-bg-secondary: #161b22;
--color-accent-teal: #00adb5;
--color-accent-rose: #e2725b;
--font-heading: 'Poppins', system-ui, sans-serif;
--font-body: 'Inter', system-ui, sans-serif;
--shadow-card: 0 4px 24px rgba(0, 0, 0, 0.3);
}
This approach has several advantages:
var() syntaxIf you're migrating from v3, the
@tailwindcss/upgradeCLI handles most of the conversion automatically. It reads your JavaScript config and generates the equivalent@themeblock.
At Rosecraft Studios, we organize our @theme block into semantic categories:
@theme {
/* === Colors === */
--color-bg-primary: #0d1117;
--color-bg-secondary: #161b22;
--color-bg-card: #131920;
--color-accent-teal: #00adb5;
--color-accent-rose: #e2725b;
--color-text-primary: #e6edf3;
--color-text-muted: #8b949e;
/* === Typography === */
--font-heading: 'Poppins', system-ui, sans-serif;
--font-body: 'Inter', system-ui, sans-serif;
/* === Shadows === */
--shadow-card: 0 4px 24px rgba(0, 0, 0, 0.3);
--shadow-teal-glow: 0 4px 16px rgba(0, 173, 181, 0.25);
}
Then in components, we use only the token names — never raw hex values:
<div className="bg-bg-card border border-border rounded-lg p-6">
<h3 className="font-heading text-text-primary text-xl font-semibold">Card Title</h3>
<p className="font-body text-text-muted">Card description</p>
</div>
This discipline pays off when a client requests a theme adjustment. Changing --color-accent-teal from #00adb5 to #0891b2 updates every component that uses it — instantly, with zero search-and-replace.
Tailwind v4 eliminates the content array configuration. The new engine automatically detects which files use utility classes:
/* v3: Required explicit content paths */
/* content: ['./src/**/*.{js,ts,jsx,tsx}'] */
/* v4: Just import and it works */
@import 'tailwindcss';
Automatic detection has exclusions, including ignored files and dependencies. Use @source to register additional directories, such as shared components in a monorepo:
@import 'tailwindcss';
@source "../shared/components";
@source "./src";
Container queries — long a CSS wish-list feature — are first-class in v4:
<div className="@container">
<div className="@sm:flex @sm:gap-4 @md:grid @md:grid-cols-3">
{/* Layout responds to container width, not viewport */}
</div>
</div>
Container queries are especially powerful for component libraries. A card component can adapt its layout based on the space available to it, regardless of where it's placed in the page.
Record clean-build time, rebuild time after a representative edit, generated CSS size, and peak memory before and after the migration. Use the same machine and dependencies, repeat the measurements, and keep the output alongside the pull request. A faster compiler does not automatically mean a faster page for visitors.
The migration isn't entirely seamless. Key breaking changes:
Review the official upgrade guide for renamed shadow and radius utilities, ring defaults, and browser requirements. Use a representative set of pages for visual checks, including focus, hover, and responsive states.
@plugin loads a legacy JavaScript plugin. It does not replace the JavaScript plugin() helper with a CSS file loader:
@import 'tailwindcss';
@plugin '@tailwindcss/typography';
For a utility defined in CSS, use @utility:
@utility content-auto {
content-visibility: auto;
}
See the directive reference.
The dark variant uses prefers-color-scheme by default. To control it through a .dark class, override the variant:
@import 'tailwindcss';
@custom-variant dark (&:where(.dark, .dark *));
See Tailwind's dark-mode documentation.
Check browser support and plugin compatibility first. Run the upgrade tool on a branch, review the generated changes, then compare key layouts and interaction states. Treat a migration as a code and visual review, with enough room to investigate regressions.
Need help with a Tailwind v4 migration or building a design system? Reach out — we've done this for multiple production applications and know where the gotchas are.
With your permission, Google Analytics helps us understand which pages people visit. Analytics cookies stay off until you accept. You can change this in Cookie settings.