CSS-in-JS to CSS Modules: Performance Migration Guide
QUICK ANSWER
GitHub reported on September 25, 2026 that github.com completed a multi-year migration away from its CSS-in-JS path toward CSS Modules and native CSS. The important lesson is not that every application should immediately remove CSS-in-JS: GitHub first measured a real scaling problem, then migrated incrementally behind feature flags, compared visual-regression output, preserved a compatibility layer, and rolled changes out gradually. GitHub reports that its Primer component migration produced 55% less server-side render time and 25% less component initialization time in its environment, while later page-level sx migrations showed SSR improvements ranging from about 1% to 22% on measured pages. Treat those figures as GitHub-specific evidence, establish your own baseline, and migrate only where runtime styling cost is actually material.
Server-side rendering time rises as styled-component count grows
Initial page rendering waits on client-side style initialization
Dynamic style objects create measurable runtime work on dense pages
A design-system upgrade is blocked by legacy CSS-in-JS or sx usage
A team wants to remove a styling runtime but cannot safely rewrite every component at once
Possible causes
Runtime styling can add client initialization and server style-collection work
Highly dynamic inline style objects can scale poorly as component count grows
A design system may need a compatibility bridge while product code migrates
Large styling migrations create visual-regression risk when performed as one big rewrite
Performance claims from another application can be misleading without workload-specific measurement
HOW TO FIX IT
Work from the safest step to the harder repair.
Step 1. Measure before changing architecture. Capture representative server-render time, client initialization/hydration cost, CSS/JS transfer size, interaction timing and visual-regression baselines on pages where styling work appears expensive.
Step 2. Inventory the actual runtime styling surface: styled-components or equivalent imports, sx-style object props, dynamic theme branches, generated class names and components whose appearance depends on runtime-only values.
Step 3. Choose a static target only where it fits the styling contract. CSS Modules are useful when styles can be compiled ahead of time and scoped locally, but truly user-defined or data-dependent values may still need CSS custom properties, inline values or another bounded runtime mechanism.
Step 4. Migrate the design-system layer first when it owns a large share of styling behavior. Preserve the public component API where practical so product teams do not have to rewrite every call site in the same release.
Step 5. Use a compatibility bridge for legacy consumers instead of forcing an all-at-once cutover. GitHub describes a wrapper package that temporarily preserved sx-style usage while direct consumers moved to the lower-runtime path.
Step 6. Gate migrated components or packages so old and new styling can be compared under the same workload. Roll out to internal users or a small cohort before broad release.
Step 7. Run visual-regression and accessibility checks for every migrated component state, including focus, hover, disabled, loading, high-contrast and supported theme variants. Pixel equivalence alone does not prove semantic or keyboard behavior is preserved.
Step 8. Compare production-like performance after each coherent batch. Attribute gains to the migrated surface rather than assuming every page will match GitHub's reported percentages.
Step 9. Remove the compatibility layer only after search confirms no supported consumers still depend on it and rollback has been tested.
Step 10. After the runtime dependency is removed, review the final CSS delivery strategy for duplication, unused rules, cacheability and route-level loading so a successful runtime migration does not simply replace JavaScript cost with uncontrolled stylesheet weight.
Need the actual code? Go to GenesisCodeDoctor.com to search the Code Store or request code for the exact platform, error, and repair you are working on.
1. Is styling runtime cost actually visible in profiling? If no, prioritize the larger measured bottleneck.
2. Are most styles static or token-driven? If yes, compile-time CSS such as CSS Modules is a strong candidate; if no, isolate the genuinely dynamic subset first.
3. Can the design system preserve its public API during migration? If yes, use an internal compatibility bridge and staged rollout.
4. Do visual, accessibility and performance checks remain clean after a batch? If no, stop the rollout and compare old/new behavior before migrating more call sites.
5. Has the last legacy consumer been removed and rollback tested? Only then remove the CSS-in-JS compatibility package or wrapper.
REPAIR FLOW
A visual path from symptom to verified production.
Observe→
Protect→
Isolate→
Repair→
Test→
Publish→
Verify live
BEFORE YOU PASTE CODE
Protect the working site first.
Keep migration batches reversible and independently deployable.
Use CSS custom properties for bounded dynamic values rather than rebuilding a general runtime style engine inside component code.
Test supported themes and high-contrast modes explicitly because theming dependencies can survive after the main CSS-in-JS library is removed.
STOP AND GET HELP WHEN
Do not turn a repair into a larger outage.
Do not rewrite a stable styling stack solely because GitHub changed its own architecture; first demonstrate a meaningful bottleneck in your workload.
Do not quote GitHub's 55%, 25% or 1–22% improvements as a forecast for another application.
Do not remove a compatibility layer while supported components or themes still depend on it.
Do not trade away accessibility, theme correctness or visual stability for a narrower performance metric.
HOW GENESIS HANDLES IT
Diagnose the exact failure before choosing a repair.
Genesis separates the visible symptom from the underlying technical cause. Run the supported diagnostic first, review the evidence, and then use a matching repair only when the failure is actually verified.
Platform scope
React · CSS Modules · CSS-in-JS · Design systems · SSR
Does GitHub's migration prove CSS-in-JS is always slow?
No. GitHub documented a scaling problem in its own component-heavy environment. The transferable lesson is to measure runtime styling cost and migrate incrementally when that cost is material.
Why did GitHub use CSS Modules?
GitHub says CSS Modules preserved local class-name scoping and component-adjacent authoring while moving style work out of client/server runtime execution and into generated stylesheets.
Should I migrate every dynamic style to a class?
Not necessarily. Static and token-driven styles are good compile-time candidates, while truly dynamic numeric or user-controlled values may be safer and simpler as validated CSS custom properties or narrowly scoped inline values.
How should I judge whether the migration worked?
Compare your own pre/post rendering, initialization, interaction, transfer-size and regression data under representative traffic and component states; do not judge success from a third-party benchmark alone.
Start with a free diagnostic. If Genesis verifies a problem and a compatible treatment exists, continue to the matching Code Store product or repair path. If you cannot find the exact code you need, request it at GenesisCodeDoctor.com rather than forcing a generic snippet into the wrong platform.