Migration

Migrating existing CSS

Good migration is not heroic rewrites. It is controlled improvement. You should not need to pause delivery, rebuild the whole frontend, or pretend the old CSS is not still in the room.

Ask this first

Ask first: Can this be safely replaced now?

  • Yes — replace properly.
  • No — contain it and improve around it.

Most migration mistakes come from trying to fix everything at once. Decide whether the code should be replaced or safely contained.

Migration principles

Contain first

Put existing CSS somewhere predictable before changing how new CSS is written.

Improve active code

Fix the CSS people touch every week, not the fossil no one has opened since 2018.

Delete over time

Migration succeeds when legacy CSS gets smaller, not when it gets renamed and promoted.

Recommended migration path

  1. Introduce the layer order first.
  2. Move old CSS into the legacy layer.
  3. Put tokens and settings in the settings layer.
  4. Move broad element defaults into base.
  5. Write all new work as proper component partials.
  6. Reduce selector depth when touching existing code.
  7. Replace unclear names with semantic component ownership.
  8. Use modifiers for variants and state classes for temporary state.
  9. Move emergency fixes into hacks with comments.
  10. Delete old CSS when the UI is replaced.

Common migration milestones

  • Milestone 1: Layer order is defined and legacy CSS is isolated.
  • Milestone 2: New component work follows naming, state, and token rules.
  • Milestone 3: Legacy selectors shrink release by release.
  • Milestone 4: Hacks are tracked and retired on a regular cadence.

Expected effort range

  • Small codebase: 1-3 sprints for a stable migration baseline.
  • Mid-size codebase: 1-2 quarters for broad consistency.
  • Large or multi-team codebase: phased migration over multiple quarters.

Step 1: define the cascade order

Add layer order before moving code. This gives the project a stable override model immediately and stops specificity wars from breeding.

CSS code example
@layer legacy, settings, base, utilities,
layout, components, theme, hacks;

Step 2: isolate legacy CSS

Legacy CSS belongs in the legacy layer so the rest of the project can move forward without pretending old code is modern architecture.

CSS code example
@import './legacy/site.css' layer(legacy);
@import './components/product-card.css' layer(components);

Importing old CSS first means every intentional layer above it has clearer ownership and safer override behaviour.

What not to do

  • Do not rename every class and call it migration.
  • Do not move legacy CSS into components and call it clean.
  • Do not let hacks become permanent architecture.
  • Do not add specificity when layer order solves the problem.
  • Do not block delivery for a rewrite plan with no clear business case.

Migration should reduce risk, not create a dramatic new source of it.

Definition of done

Migration is working when new CSS follows the system, old CSS is contained, overrides are predictable, and the legacy layer keeps shrinking over time.

Next useful pages