This article details GitHub's extensive multi-year migration from a CSS-in-JS solution (styled-components with `sx` prop) to CSS Modules for their Primer Design System and broader codebase. The primary motivation was to address performance challenges related to client-side style initialization, server-side rendering overhead, and scalability issues as their component count grew. The migration involved a phased approach utilizing feature flags, wrapper components, automated tooling, and a significant engineering effort to achieve substantial performance gains and simplify their frontend architecture.
Read original on GitHub EngineeringGitHub's Primer Design System, powering many of its UI experiences, faced significant performance challenges with its existing CSS-in-JS solution. As the number of components on pages increased, the overhead of client-side style initialization and server-side rendering (SSR) became substantial. This architectural decision, while offering benefits like TypeScript support and co-location, introduced runtime costs due to the dynamic nature of inline objects used for styling, impacting initial page load times and overall scalability.
The Primer team identified CSS Modules as a suitable alternative. This approach allows for native CSS features with built-in encapsulation (local class names by default), significantly reducing the risk of global selector collisions. Crucially, CSS Modules eliminate client and server runtime behavior; styles are compiled into static CSS stylesheets and sent as part of the HTML, directly addressing the performance bottlenecks of CSS-in-JS.
Performance Wins Achieved
The migration yielded significant performance improvements: a 55% reduction in server-side rendering time for Primer components and a 25% decrease in component initialization time. This demonstrates the impact of moving dynamic, runtime-heavy styling to a static, compile-time approach in large-scale applications.
This case study highlights the importance of incremental re-platforming for large-scale systems, where significant architectural shifts are introduced gradually with robust safety nets like feature flags, comprehensive testing, and automated migration tooling. It underscores how even frontend styling choices can have profound impacts on server-side performance, deployment complexity, and overall developer experience.