All posts
Web design & development

Next.js + Tailwind v4 for Marketing Sites: A Practical Setup

Set up a Next.js Tailwind marketing site with Tailwind v4: CSS-first config, design tokens in @theme, fluid type, dark mode and the v3 habits to drop.

By Mehdi Hassan6 min read

The short answer

To set up a Next.js Tailwind marketing site with Tailwind CSS v4, install tailwindcss and the @tailwindcss/postcss plugin, import Tailwind at the top of your global CSS, and define brand tokens inside an @theme block. There's no JavaScript config file by default: colors, fonts and spacing live in CSS as variables your components share.

Key takeaways

  • Tailwind v4 is configured in CSS: one import line plus an @theme block replaces tailwind.config.js.
  • Every token in @theme becomes both a utility class and a CSS variable you can use anywhere.
  • Name tokens semantically, like ink and accent, so the same names work in Figma and code.
  • Content files are detected automatically; use @source only for packages outside your project.
  • Several v3 utilities were renamed, so upgrades need a pass with the official upgrade tool.

Part of Next.js for Marketing Websites: When It's the Right Choice

How do you set up a Next.js Tailwind marketing site with Tailwind v4?

You set up Tailwind v4 in Next.js with three moves: install the packages, register the PostCSS plugin, and import Tailwind in your global stylesheet. Everything else, including your brand tokens, is written in CSS.

That's a real change from Tailwind v3, where most setup happened in a JavaScript config file. For a marketing site it's a good change: tokens are plain CSS variables, so they're visible in the browser, easy to theme and simple to share with non-Tailwind code. If you're still deciding whether a coded site suits your team, start with Next.js for a marketing website.

  1. Install the packages

    Add tailwindcss, @tailwindcss/postcss and postcss as dev dependencies. Recent create-next-app versions can set this up for you.

  2. Register the PostCSS plugin

    In postcss.config.mjs, export a plugins object containing "@tailwindcss/postcss": {}. No autoprefixer is needed; v4 handles vendor prefixes.

  3. Import Tailwind

    At the top of app/globals.css, add @import "tailwindcss"; and import that stylesheet in your root layout.

  4. Define tokens in @theme

    Below the import, add an @theme block with your colors, fonts, spacing and breakpoints as CSS variables.

  5. Wire fonts through next/font

    Load fonts with next/font, expose each as a CSS variable on the html element, and point your font tokens at those variables.

  6. Check the build

    Run the dev server, confirm utilities like bg-ink and font-display work, and check that production CSS only includes classes you use.

How do you define design tokens in Tailwind v4?

Define design tokens in Tailwind v4 by declaring CSS variables inside @theme using Tailwind's namespaces. A variable named --color-ink creates utilities like bg-ink, text-ink and border-ink, and stays available as var(--color-ink) for any custom CSS.

Namespace

Example token

Utilities it creates

--color-*

--color-ink: oklch(0.2 0.02 260);

bg-ink, text-ink, border-ink

--font-*

--font-display: var(--font-serif);

font-display

--text-*

--text-hero: clamp(2.5rem, 6vw, 5rem);

text-hero

--spacing

--spacing: 0.25rem;

p-4, gap-6, mt-12 scale from one base

--breakpoint-*

--breakpoint-3xl: 112rem;

3xl: variant

--radius-*

--radius-card: 1.25rem;

rounded-card

--ease-*

--ease-out-soft: cubic-bezier(0.2, 0.8, 0.2, 1);

ease-out-soft

If you want only your tokens and none of Tailwind's default palette, reset a namespace first with a line like --color-*: initial; inside @theme. On marketing sites we usually do this for colors, so nobody reaches for a stray default blue, and keep the default spacing scale.

How should you handle fluid type and section spacing?

Handle fluid type and spacing with clamp() values stored as tokens, so headings and section padding scale smoothly between phone and desktop without a pile of breakpoint classes. Marketing pages have big type and generous rhythm, which is where clamp() pays off.

  • Display sizes as tokens: --text-hero and --text-section with clamp() values, used as text-hero and text-section.
  • Body copy stays fixed: keep base text at a readable fixed size and only scale headings.
  • Section rhythm as a variable: define a --section-space variable and use it as py-(--section-space), the v4 shorthand for arbitrary CSS variables.
  • Container width as a utility: create a container utility with @utility so every section aligns to the same column.

Keeping these decisions in tokens means a designer can tune the whole site's rhythm in one file, and layout shifts stay predictable, which helps the scores covered in our Core Web Vitals fixes for Framer, Webflow and Next.js.

How do you add dark mode and custom variants?

Add class-based dark mode in v4 with a custom variant: @custom-variant dark (&:where(.dark, .dark *)); in your CSS. Without it, the dark: variant follows the visitor's system preference, which is fine for many marketing sites.

A cleaner pattern for themed sections is to switch token values instead of writing dark: everywhere. Give a section a data-theme attribute, and redefine --color-ink and --color-paper for that attribute in plain CSS. Every utility inside then flips automatically. This is also how we handle dark hero bands on otherwise light pages.

Example: a minimal globals.css for a marketing site

For example, a lean starting file might contain, in order: the line @import "tailwindcss"; then an @theme block that resets --color-* to initial and defines --color-ink, --color-paper, --color-accent and --color-muted; --font-sans and --font-display pointing at next/font variables; --text-hero and --text-section with clamp() values; and --radius-card.

After that, a @custom-variant line for class-based dark mode, a @utility container rule with max-width and side padding, and a small [data-theme=dark] block that swaps ink and paper. That's the whole design-token layer for most startup sites.

What changed from Tailwind v3 that trips people up?

The changes that trip people up are the move from JavaScript to CSS config, automatic content detection and a handful of renamed utilities. Projects upgraded by hand often look almost right, with small spacing, shadow and ring differences.

v3 habit

v4 reality

tailwind.config.js for everything

@theme in CSS; a JS config only via @config for legacy setups

content array of file globs

Automatic detection; @source for extra paths such as a shared package

@tailwind base, components, utilities

One @import "tailwindcss" line

shadow-sm, rounded-sm, blur-sm

Renamed to shadow-xs, rounded-xs, blur-xs; the bare names shifted up a step

outline-none

outline-hidden for the old behavior

ring is 3px by default

ring is 1px; use ring-3 for the old look

Plugins in the JS config

@plugin directive in CSS

Does Tailwind affect marketing site performance?

Tailwind itself is light: v4 generates only the classes you use, so production CSS for a marketing site stays small. Performance problems on Tailwind sites usually come from elsewhere, like heavy client components, animation libraries or third-party scripts.

Two habits help. Keep animation in CSS transitions and Tailwind's transition utilities where you can, rather than a JavaScript library for every hover. And keep interactive components small, since hydration cost, not CSS, drives slow interactions, as explained in improving INP on Next.js sites. For multilingual sites, prefer logical utilities like ms-4 and pe-6 over ml-4 and pr-6, so right-to-left languages work without overrides; our guide to multilingual Next.js sites covers the routing side.

This is the stack we build on ourselves: Next.js, Tailwind v4 and design tokens mirrored in Figma. Our fixed-price website is $8,000 for up to six pages if you'd rather have the setup, sections and CMS done for you; see pricing.

Frequently asked questions

Do I still need tailwind.config.js in Tailwind v4?
No. A new Tailwind v4 project needs no JavaScript config. Tokens go in @theme, plugins load with @plugin and extra content paths use @source, all in your CSS. If you're migrating a large v3 project and need time, you can keep the old file and load it with the @config directive while you move settings over.
Can I use Tailwind v4 with CSS modules in Next.js?
Yes. Use Tailwind utilities in your components and CSS modules for anything that's easier in plain CSS. Inside a module, reference tokens as CSS variables, such as var(--color-accent). If you need Tailwind's @apply or theme functions in a module, add an @reference line pointing to your main stylesheet so the module knows about your tokens.
Is Tailwind v4 supported in all browsers?
Tailwind v4 targets modern browsers, because it relies on features like cascade layers, registered custom properties and color-mix(). Current versions of Chrome, Safari, Firefox and Edge are supported. If you must support much older browsers, check the official compatibility notes before upgrading, or stay on v3 for that project.
Should marketing sites use a component library with Tailwind?
A headless component library can save time on accessible menus, dialogs and tabs, then you style it with your own tokens. Avoid importing a fully styled kit, because marketing sites need a distinct look and you'll spend more time overriding styles than you saved. Build sections yourself on top of a few accessible primitives.
How do I share Tailwind tokens with a CMS or email templates?
Because v4 tokens are CSS variables, any page that loads your stylesheet can use them, including CMS preview screens. For email, which doesn't support variables reliably, export the token values into a small JSON or TypeScript file and use those values directly. Keep one source and generate the other from it.

· CEO & Design Director

Copywriter, designer and developer, and founder of Designify Studio. Over five years, 60+ projects across 14+ industries, for startups that have raised $300M+.

Want this done for you? Website, $8,000.

A multi-page marketing site, designed by us, developed in Next.js and animated. $8,000, one-time, up to 6 pages. Book a free 30-minute call to see if it fits.

Schedule Call