Skip to main content
ASoc
Comparison

Next.js vs. Tailwind CSS: They Don't Compete, and the Glue Is 5 Lines

Next.js routes and renders; Tailwind generates CSS. Measured on this repo: 876 static pages, one 15 KB gzipped stylesheet, no Tailwind config file.

The ASoc Team7 min read

Next.js and Tailwind CSS are not competitors: Next.js is a React framework that routes, renders and bundles your app, and Tailwind is a CSS generator that turns the class names in your markup into a stylesheet. Neither can do the other's job. You pick Next.js or another framework, and Tailwind or another way to write CSS — and this storefront uses both, with five lines of glue between them.

The numbers below come from that codebase: 876 prerendered pages, one 85 KB stylesheet (15 KB gzipped), no tailwind.config file, and a 133-line globals.css.

What each one actually is

Next.jsTailwind CSS
LayerApplication frameworkStyling tool
DecidesURLs, rendering (static/server/client), data loading, bundlingWhat CSS exists and what the classes are named
OutputHTML, JavaScript chunks, route handlersOne CSS file
Runs whenBuild time and request timeBuild time only
ReplacesCreate React App, Remix, Astro, a hand-rolled routerSass, CSS Modules, styled-components, hand-written CSS
Needs the other?No — it ships CSS support but no opinion about itNo — it works in any bundler, framework or plain HTML

The confusion has a reason. Both appear in the first command of most tutorials, and both show up in package.json of nearly every modern landing page. But the question they answer is different. "Should I use Next.js or Remix?" is a real fork. "Should I use Next.js or Tailwind?" has no fork in it: there is no version of the project where choosing one removes the need to decide about the other.

The glue is five lines

Next.js supports global CSS and PostCSS out of the box, and Tailwind v4 ships as a PostCSS plugin. That is the whole integration. This is the entire postcss.config.mjs:

const config = {
  plugins: {
    "@tailwindcss/postcss": {},
  },
};

export default config;

And the top of src/app/globals.css, imported once from src/app/layout.tsx:

@import "tailwindcss";

/* Class-based dark mode (toggled by adding `dark` to <html>) */
@custom-variant dark (&:where(.dark, .dark *));

@theme {
  --font-sans: var(--font-outfit), ui-sans-serif, system-ui, sans-serif;

  /* Brand / primary scale */
  --color-primary: #465fff;
  --color-primary-25: #f2f7ff;
  --color-primary-50: #ecf3ff;

Nothing else connects them. Next.js does not know Tailwind exists; it sees a CSS import that passes through PostCSS. Tailwind does not know about Next.js; it scans the source files for class names and emits matching rules. The @theme block holds 38 colour tokens, and each one becomes both a CSS variable and a family of utilities (bg-primary, text-primary-50, border-primary). There is no tailwind.config.js — in v4 the configuration lives in the stylesheet. If you want the token side in depth, Tailwind design tokens walks through it.

What the pairing produced here

Measured from npm run build on this repository (Next.js 16.2.9, @tailwindcss/postcss 4.3.1):

MeasurementValue
Prerendered pages876
CSS files emitted1
CSS size85,390 bytes raw, 15,139 bytes gzipped
tsx files in src139
Route folders with a page.tsx directly under src/app23
Source lines carrying a dark: variant336
Config files for Tailwind0 (just the 5-line PostCSS config)

The single CSS file is the number that matters. Tailwind only emits rules for classes it finds in your source, so every one of those 876 pages shares one cacheable stylesheet instead of per-page CSS that grows with the site. The pages themselves are statically generated by Next.js — the framework half of the stack — which is why none of them pay a runtime styling cost either. Tailwind has no runtime; there is no CSS-in-JS library in the client bundle.

That split is the real answer to "which is faster": they affect different things. Next.js decides when and where HTML is produced. Tailwind decides how much CSS arrives with it. Neither can be traded for the other.

When each choice is actually a choice

The forks that do exist sit next to each of them, not between them.

If you are choosing…Real alternativesThis repo's call
A frameworkRemix, Astro, plain React with ViteNext.js — see React vs. Next.js for the trade
A styling approachSass, CSS Modules, styled-componentsTailwind — see Sass vs. Tailwind
Components on top of the stylingshadcn/ui, Mantine, hand-writtenHand-written — see shadcn vs. Tailwind
How to ship dark modeprefers-color-scheme only, or class-basedClass-based, via the @custom-variant above — Tailwind v4 dark mode

Two of those rows are worth a note. The first is that Tailwind works equally well inside Next.js's main competitors; the pairing is popular because both are mainstream, not because they depend on each other. The second is that Next.js's own CSS support (global stylesheets, CSS Modules, Sass) remains available alongside Tailwind. You can run Tailwind for the layout and utilities and a CSS Module for the one component whose styles you want scoped.

Where the two do interact

There are three places where the pairing has real consequences, and this codebase hit each.

Dev-server caching of @theme. Next.js's Turbopack dev server does not hot-reload changes to the @theme block. Add --color-brand: #123456 and bg-brand silently generates nothing until you restart npm run dev. This is documented in the project's CLAUDE.md precisely because it looks like a Tailwind bug and costs people twenty minutes the first time. Editing class names hot-reloads fine; editing tokens does not.

Content Security Policy. The CSP in next.config.ts has to allow 'unsafe-inline' for styles, because Tailwind output and Next.js's own runtime both inject inline <style> and <script> tags. A nonce-based policy would force every route to render dynamically per request, which would break the static pages. This is a framework-and-styling interaction neither tool's docs warn about on their own. The tradeoff is spelled out in Next.js Content Security Policy.

Class sorting. With 818 className literals across the components, unsorted utility classes turn diffs into noise. The Prettier setup uses prettier-plugin-tailwindcss with "tailwindStylesheet": "./src/app/globals.css" so the plugin reads the v4 tokens rather than a config file that does not exist.

Which should I learn first

If you…Start with
Know React and want to ship a site with routing and SEONext.js — it gives you pages, metadata and static generation
Know HTML/CSS and want to build layouts quicklyTailwind — it works in a single HTML file
Are building a marketing pageBoth; this is the stack the repository's templates are built on
Are building a pure client-side app with no SEO needTailwind alone, with whatever bundler you already have

Learning order matters less than people expect, because the two barely touch. A weekend on Tailwind transfers to any framework you move to later.

Mistakes and troubleshooting

SymptomCauseFix
"Should I pick Next.js or Tailwind?"Category error — they solve different problemsPick a framework and a styling approach independently
bg-brand renders nothing after adding a tokenTurbopack does not hot-reload @themeRestart npm run dev
Tailwind classes are missing in production onlyThe class name is built dynamically (`bg-${color}-500`) so the scanner never sees itWrite complete class names, or map to them with a lookup object
Styles work in dev but a nonce-strict CSP blocks themInline <style> injected by the toolchainAllow 'unsafe-inline' for styles, or move to per-request nonces and accept dynamic rendering
Dark mode does not toggleThe dark variant defaults to prefers-color-schemeDeclare @custom-variant dark as in globals.css and toggle .dark on <html>
Class order churns in every pull requestNo formatter owns the orderAdd prettier-plugin-tailwindcss and point tailwindStylesheet at the CSS entry

Frequently asked questions

Is Tailwind CSS a replacement for Next.js? No. Tailwind generates CSS; it has no routing, rendering or data loading. If you remove Next.js you still need something to build pages and serve them.

Do I need Tailwind to use Next.js? No. Next.js includes support for global CSS, CSS Modules and Sass, so it works with any styling approach. Tailwind is a popular default, not a requirement.

Does Tailwind slow down a Next.js site? It does not add runtime cost: it compiles at build time and ships plain CSS. This repo's 876 pages share one 15 KB gzipped stylesheet.

Can I use Tailwind CSS with Next.js server components? Yes. Classes are just strings in markup, so they work in Server and Client Components alike. All seven atoms in this codebase are Server Components.

Templates in this post

ASoc Coin is an online-banking marketing site built around a cash-overview dashboard mock and a three-tier pricing page. ASoc Compound is an automated-investing marketing site with goal-based portfolios and three-tier pricing. ASoc Cortex is an AI-agency marketing site covering services, industries, case studies and a lead funnel.

All three are Next.js + Tailwind v4 projects wired exactly as above. Browse the full sets: Next.js landing page templates, Tailwind landing page templates.

Keep reading

Comparison8 min read

Next.js vs. Vue: The Reactivity Primitive You Don't Need

Vue's Composition API needs ref/computed for every stateful value, server or client. This storefront's 13 dependencies carry zero state library — here's why.

Read more
Comparison7 min read

One-Time Payment vs Subscription: What the Webhook Handler Has to Know

Our entitlement engine is 75 lines with two status states; our LemonSqueezy webhook recognizes two event names. That's not a shortcut — it's the real cost gap between the two pricing models.

Read more
Comparison8 min read

Playwright vs Vitest: Why This Repo Runs Both for Unrelated Jobs

Vitest is a committed dependency gating 305 tests on every push. Playwright is deliberately not a dependency at all — installed ad hoc for a script that runs a few times a year.

Read more