Lesson 60 of 81
CSS Modules can be imported from any component; a global stylesheet can only be imported from the root layout. That restriction isn't arbitrary — it's what keeps the App Router's per-route bundling predictable.
12 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
This topic is about judgment and practical tradeoffs more than a single right answer — a mock interview is the better way to test yourself on it.
Be interviewed on this →Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
Next.js supports two ways to write CSS, and they're allowed to be imported from different places on purpose.
A CSS Module (button.module.css) scopes every class name to the component that imports it — the build tool hashes each class name so .button in one file can never collide with .button in another. Because each module's classes are isolated, a CSS Module can be imported from any component, anywhere in the tree, and it only ever affects that component.
Global CSS (a plain .css file with unscoped selectors like body { margin: 0; }) has no such isolation — every selector in it can affect the entire page, everywhere, all at once. Next.js enforces that a global stylesheet can only be imported from the root layout (app/layout.tsx), not from an arbitrary component. This isn't a style guideline — it's an actual build-time restriction the App Router enforces.
/* app/components/Button.module.css */
.button {
padding: 0.5rem 1rem;
border-radius: 6px;
}
// app/components/Button.tsx
import styles from "./Button.module.css";
export function Button({ children }: { children: React.ReactNode }) {
return <button className={styles.button}>{children}</button>;
}
styles.button isn't the string "button" — it's something like "Button_button__a1b2c", generated at build time so this component's .button class can never collide with another component's .button class, no matter how deep it's nested or how many other modules exist.
Global CSS, by contrast, is imported exactly once, in the root layout:
// app/layout.tsx
import "./globals.css";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
Trying that same import "./globals.css" from inside Button.tsx instead is a build error, not a style mistake caught in review — the App Router rejects it outright.
className={styles.button} only works if the class actually exists in the module file. A typo — styles.buton — doesn't error at build time in the way a missing import would; it silently resolves to undefined, and the element renders with no class applied.globals.css, and CSS Modules for everything else — the two coexist by design, they're just not interchangeable for the same job.This project's own token system — primitive, semantic, and component-level CSS variables in globals.css — is exactly the kind of thing that belongs in global CSS: values genuinely meant to apply everywhere, consumed by name from any component's CSS Module. A CSS Module can freely reference a global custom property like var(--color-primary) without importing anything extra — scoping applies to class names, not to the custom properties a scoped rule is allowed to read.