CSS Modules
CSS Modules solve the biggest weakness of Global CSS — name collisions — with a simple naming convention: any file named
*.module.css gets its class names automatically scoped to the component that imports it. No configuration, no plugin to install; it works out of the box in every Next.js app.A worked example
components/Button.module.css
CSS
.button {
padding: 8px 16px;
border-radius: 6px;
border: none;
background-color: #0070f3;
color: white;
font-weight: 600;
cursor: pointer;
}
.button:hover {
background-color: #0059c1;
}
.secondary {
background-color: transparent;
color: #0070f3;
border: 1px solid #0070f3;
}components/Button.tsx
TSX
import styles from './Button.module.css'
export default function Button({
children,
variant = 'primary',
}: {
children: React.ReactNode
variant?: 'primary' | 'secondary'
}) {
return (
<button
type="button"
className={variant === 'secondary' ? styles.secondary : styles.button}
>
{children}
</button>
)
}At build time, Next.js rewrites
.button into something unique like Button_button__x8f2a, and the imported styles object maps the original name to that generated one. Two components can each define a class called .button in their own module without any risk of one overriding the other.Composing classes and using clsx
Because
styles.button is just a string, combining conditional classes works the same way it would with any other CSS approach — template literals or a small utility library both work fine.TSX
import styles from './Card.module.css'
export default function Card({ highlighted }: { highlighted?: boolean }) {
return (
<div className={`${styles.card} ${highlighted ? styles.highlighted : ''}`}>
Card content
</div>
)
}Note
CSS Modules work in both Server and Client Components — importing a
.module.css file doesn't require 'use client'. The class-name rewriting happens entirely at build time, so there's no runtime cost and no client-side JavaScript involved.Tip
CSS Modules also support
composes, letting one class inherit the rules of another defined in the same or a different module — useful for a small set of shared base styles without reaching for Sass.Any file ending in
.module.cssgets its class names automatically scoped — no extra config required.Import it as an object (
styles) and reference class names as properties (styles.button).Two components can reuse the same class name in their own modules with zero collision risk.
Works in both Server and Client Components since the scoping happens at build time, not runtime.