Back to CSS
CSS
medium
mid

How would you manage styles in a large scale application using CSS in JS, CSS variables, or other approaches?

At scale the real problems are global scope, specificity wars, dead code, and theming. Pick a scoping strategy — CSS Modules, CSS-in-JS (runtime or zero-runtime), or utility-first (Tailwind) — layered with design tokens as CSS custom properties for theming. There's no single right answer; the senior move is matching the choice to team size, SSR needs, and performance budget.

6 min read·~10 min to think through

Styling a large app isn't about picking a "best" library — it's about solving the scaling problems of plain CSS: global namespace collisions, specificity wars, dead-code accumulation, inconsistent design, and theming.

The strategies, and their trade-offs

1. CSS Modules Locally-scoped class names (styles.buttonbutton_a3f9x). Solves global scope with zero runtime cost and plain CSS. Great default. Downside: dynamic/prop-based styling is awkward (you toggle classes).

2. CSS-in-JS (runtime — styled-components, Emotion) Styles colocated with components, full access to props/theme, dynamic styling is natural. Downside: runtime cost (style injection, serialization), SSR setup complexity, and it's fallen out of favor in the React Server Components era because it needs client JS.

3. Zero-runtime CSS-in-JS (vanilla-extract, Linaria, Panda CSS) CSS-in-JS authoring ergonomics, but styles are extracted to static CSS at build time — no runtime. Best of both for many teams; works with RSC/SSR.

4. Utility-first (Tailwind) Compose styles from utility classes. No naming, tiny purged output, enforced consistency via the config (design tokens baked in), great for big teams. Downside: verbose markup, learning curve, harder for highly dynamic one-off styling.

5. Design tokens via CSS custom properties This is orthogonal — layer it under any of the above. --color-primary, --space-md in :root give you one source of truth, runtime theming, and dark mode with no JS. The modern stack is "a scoping strategy + custom properties for tokens/theming."

How to actually decide

ConcernLeans toward
RSC / minimal client JSCSS Modules, zero-runtime CSS-in-JS, Tailwind
Highly dynamic, prop-driven stylesCSS-in-JS (runtime or zero-runtime)
Large team, consistency, velocityTailwind + token config
Existing CSS expertise, simplicityCSS Modules
Theming / dark modeCSS custom properties (with any of the above)

The non-negotiables at scale (whatever you pick)

  • Scoped, not global — pick something that kills naming collisions.
  • Design tokens — a single source of truth for color/spacing/type.
  • A component library / design system — styles live with reusable components.
  • Purging / tree-shaking — dead CSS must be removable.
  • A linter (Stylelint) and conventions.

Senior framing

The senior answer refuses the false dichotomy. It names the actual problems (scope, specificity, dead code, theming, consistency), maps solutions to constraints (SSR/RSC, team size, dynamism, perf budget), and notes the current consensus: zero-runtime scoping (CSS Modules / vanilla-extract / Tailwind) + CSS custom properties for tokens, with runtime CSS-in-JS losing ground due to the server-components shift. "It depends — here's on what" beats "X is best."

Follow-up questions

  • Why has runtime CSS-in-JS lost favor with React Server Components?
  • How do CSS custom properties complement any styling approach?
  • What's the difference between runtime and zero-runtime CSS-in-JS?

Common mistakes

  • Claiming one approach is universally best.
  • Ignoring the SSR/RSC implications of runtime CSS-in-JS.
  • No design-token / theming strategy.
  • No purging — CSS grows unbounded.

Edge cases

  • Migrating styling strategy mid-project is costly — choose deliberately.
  • Mixing approaches (CSS Modules + Tailwind) is common but needs conventions.
  • Runtime CSS-in-JS can cause hydration/style-flash issues if SSR isn't set up right.

Real-world examples

  • Design systems, multi-team apps, white-label/themed products.

Related questions