devnotes.

Styling in Next.js

Next.js supports several styling approaches out of the box; most real projects combine two or three of them.

Global CSS

Imported once, typically in the root layout, and applies everywhere:

/* app/globals.css */
:root { --color-primary: #0070f3; }
body { margin: 0; font-family: system-ui, sans-serif; }
// app/layout.tsx
import './globals.css';

CSS Modules — scoped by default

A file named *.module.css is automatically scoped to the component that imports it, so class names never collide across the app:

/* Card.module.css */
.card {
  border: 1px solid #eaeaea;
  border-radius: 8px;
  padding: 1rem;
}
import styles from './Card.module.css';

export default function Card({ children }: { children: React.ReactNode }) {
  return <div className={styles.card}>{children}</div>;
}

Tailwind CSS — the most common choice today

create-next-app offers Tailwind as a setup option; utility classes are written directly in JSX and compiled/purged at build time:

export default function Card({ children }: { children: React.ReactNode }) {
  return (
    <div className="rounded-lg border border-gray-200 p-4 shadow-sm">
      {children}
    </div>
  );
}

Tailwind pairs particularly well with the App Router because utility classes work identically whether a component is a Server or Client Component — no runtime JS is needed to apply styles.

A note on CSS-in-JS libraries

Older CSS-in-JS libraries (styled-components, Emotion) that generate styles at runtime need special handling to work with Server Components, since they typically rely on React context and client-side style injection. Some libraries now ship App Router-compatible setups, but many teams migrate to Tailwind or CSS Modules specifically to avoid this friction — check a library's current App Router support before adopting it for a new project.

next/font — self-hosted, zero-layout-shift fonts

import { Inter } from 'next/font/google';

const inter = Inter({ subsets: ['latin'] });

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en" className={inter.className}>
      <body>{children}</body>
    </html>
  );
}

next/font downloads and self-hosts Google Fonts at build time (no request to Google's servers at runtime) and automatically avoids layout shift by injecting the right size-adjust metrics.

Styling Options in Next.js: CSS Modules, Tailwind and Global CSS | DevNotes