1. Introduction
Building a design system is only half of the work.
Yes, it's challenging to evaluate multiple options, gather feedback from stakeholders, and implement everything in code - but this is still the part most engineers feel comfortable with. We know how to explore technologies, analyze requirements, write specifications, and eventually ship the technical foundation.
The real challenge, at least for me, was bringing this new solution into the daily life of other developers. Any new system introduces friction: it requires time, attention, and a willingness to go through the learning curve. And when teams are under roadmap pressure, people naturally gravitate toward the approaches they already know - even if those approaches caused the very problems we were trying to solve.
On top of that, some decisions that seem perfectly reasonable at the beginning may turn out to be inaccurate or incomplete - not only when they meet real-world usage across multiple teams, but also as that real world evolves faster than expected.
That's what I want to share in this final part of the series: how we handled governance, adoption, and the human side of making a design system truly work.
2. Why adoption is hard (even when the tech is good)
2.1. Common challenges familiar to any company
Adoption is rarely a technical problem - it's a human one.
Even when the new system is objectively better, teams face familiar obstacles:
- People prefer familiar tools, especially under roadmap pressure.
- New patterns require time, attention, and a mental shift.
- Legacy code feels "safe", even if it's the cause of recurring issues.
- Every team has slightly different habits, priorities, and constraints.
- Benefits of a design system are long-term, while costs are immediate.
In other words: even good technology doesn't adopt itself.
2.2. What was hard in our case
Our situation wasn't radically different from the typical one, but a few challenges stood out.
First, since our single source of truth was Figma, some of the core complexities came from the design side. Understanding the correct meaning and usage of components - like when to use a Menu, a Select, or a Popover - isn't always obvious if you haven't worked deeply with accessibility-driven patterns. Things get even more complicated when a design blends attributes of multiple components, such as a popup that allows switching accounts and shows contextual actions at the same time.
Second, the learning curve was amplified by the number of new technologies introduced at once. The design system was built in parallel with a broader transformation of our frontend architecture: new monorepo structure, the first ui-kit package, migration from styled-components to PostCSS modules, introduction of Radix Primitives, design tokens, component architecture patterns, Storybook documentation, and Chromatic visual tests.
Each of these changes was reasonable on its own - but together they naturally made adoption more demanding than it would have been with fewer moving parts.
3. Migration strategy: slow, controlled, predictable
3.1. Main principles for gradual and consistent migration
The foundation of our migration strategy was simple: move forward without breaking what already works. A full "big bang" rewrite may look tempting from an engineering perspective, but it is rarely justified for the business unless the gains are dramatic - such as a major performance improvement or a critical SEO uplift. Neither was the case for us, so gradual adoption became the most reasonable and sustainable option.
Our main principles were:
- All new features must use the new components This applied both to Figma (as the single source of truth) and to code. New work should build on the new system; legacy components should remain only where they already exist. This ensures natural growth of the new system without forcing teams into expensive rewrites.
- "If you touch it - improve it" This company-wide rule proved extremely useful. Whenever someone modifies or refactors a piece of UI, it's a good opportunity to migrate that part to the new components as well. Since the PR must already be reviewed and visually tested, merging the migration into the same change often reduces the total cost compared to doing it later as a separate task.
Together, these principles created a predictable and manageable adoption flow: slow enough not to disrupt product work, but steady enough to avoid stagnation.
3.2. Design review as part of adoption
In most teams, new designs are reviewed by a Head of Design or CPO before they are marked as Ready for Dev.
However, neither of those roles initially owned the full context of the newly introduced design system - its components, constraints, patterns, or how they translated into code.
To bridge this gap, we introduced an additional review step for the first few months: Design System Review.
This review was handled by two people who fully understood the system's architecture and principles:
- the Design System Lead from the design side, and
- the Project Lead from engineering.
This additional checkpoint produced several important benefits:
- Catching inconsistencies early Issues in component choice, naming, and patterns were flagged before any code was written.
- Knowledge sharing Designers learned how to use the new system correctly - which components to pick, how semantic tokens worked, when to use specific patterns, etc.
- Better predictability Designs handed to developers were more consistent, more realistic, and aligned with the actual capabilities of the system.
This short-lived review phase significantly accelerated adoption by ensuring that both design and engineering moved forward with the same mental model.
3.3 Developer Experience improvements
People naturally gravitate toward familiar behavior, we introduced several DX-focused guardrails to promote consistent usage of the design system and reduce friction:
- Custom ESLint rules These rules enforced correct usage of components and tokens (as mentioned in Part II). They provided immediate feedback in the editor, long before a PR review.
- Marking all legacy components as deprecated Even components not yet fully reimplemented in the new design system were flagged. This wasn't meant as pressure — just a clear visual signal that this is the old path.
- Documentation (as a last resort) Proper docs were written and maintained, but realistically, documentation works best as a safety net, not as the primary adoption tool.
- Automation scripts We built tools to export Figma variables into code, generate boilerplate for new components, and streamline contributions to the design system.
- A dedicated Slack channel Centralised communication helped teams ask questions, share examples, and stay aligned. Most importantly, it created a sense of community rather than another rule to follow.
Together, these DX additions lowered the cognitive load of using the system and made the correct path the easiest one.
And most importantly, improving DX ensured that adoption didn't rely on discipline alone - the system itself guided developers toward the right patterns.
3.4 AI: migrating in 2025 and beyond
As LLMs have become more accurate and context-aware, a significant part of manual migration work can now be delegated to them.
To make adoption smoother, we embraced Cursor and GitHub Copilot as migration assistants:
-
Automated migration guides
With a simple Cursor prompt, we generated structured guides showing how legacy component configurations should be adjusted to match the new API.
These guides could also be reused directly as transformation prompts, e.g.:
"Migrate all legacy
Buttoncomponents to the newButtonfromui-kitusingdocs/migration-guides/Button.mdx." - AI rules aligned with the design system Copilot/Cursor suggestions were adapted to prefer design-system components and patterns when generating new code. This gently nudged developers toward the correct implementation without enforcement.
- Review automation AI-assisted review rules were added to detect code that could be replaced with design-system components and leave appropriate comments. This offloaded part of the cognitive burden from reviewers and helped teams identify migration opportunities early.
AI didn't replace the adoption process - but it became a surprisingly effective accelerator, reducing repetitive work and helping teams move toward the new system with less manual effort.
This allowed us to shift our focus from mechanical migration tasks to higher-level decisions about the future of the system.
4. What worked well
Here's a summary of the practices and approaches that proved especially effective during the development and adoption of our design system:
- Unified and consistent design across new features Once components were standardized, new features automatically looked and behaved consistently across the product.
- Higher-quality components with accessibility and keyboard support built in The new components had a clearer API, fewer edge-case bugs, and predictable behavior compared to their legacy equivalents.
- A solid foundation for future technologies Introducing the first UI package in our monorepo, PostCSS instead of styled-components, Storybook as the central documentation hub, and design tokens created a long-lasting base for all upcoming UI work.
- Snapshot stories increased trust in UI changes Visual regression testing made developers more confident that refactoring or migration wouldn't break existing UI.
- DX tooling significantly reduced migration friction Boilerplate generators, token sync scripts, ESLint rules - all of these made the new path easier than the old one.
- Design review improved alignment between design and engineering This step increased designers' awareness of component architecture and helped ensure that the designs handed to engineering were consistent and implementable.
5. What I would change (and what didn't work)
Looking back almost a year after we started the project, some decisions now seem much clearer - including those I would approach differently today.
5.1. Starting the project after the engineering team scaled
The design system effort began after a period of rapid growth. This created unnecessary technical debt and onboarding complexity.
In retrospect, investing in foundational quality before scaling the team would have saved time and reduced friction later.
Newcomers have to learn the system anyway - better to onboard them into a clean, consistent foundation.
5.2. Underestimating the impact of AI evolution (as of 2024)
We couldn't predict how dramatically AI-assisted development would improve.
Today, I would lean more toward mainstream, widely adopted technologies, simply because AI models are already deeply trained on them.
More mainstream tech => better suggestions => smoother onboarding => fewer custom rules.
For example, Tailwind might have been a more AI-friendly choice than vanilla CSS modules with utilities.
5.3. Documentation should live in the codebase, not Notion
This lesson became obvious in the age of AI agents:
- Docs stored outside the repo are invisible to IDE assistants.
- To make AI truly helpful, your documentation must be co-located with code - and ideally in a format consumable by Storybook, Docusaurus, or similar tools to publish it easily.
High-level architectural docs in Notion sound nice, but they become disconnected from where development actually happens.
6. Lessons learned (my biggest challenge)
When I first imagined this project, I assumed the hardest part would be designing the system and getting leadership approval to invest in it.
I was only half right.
The real challenge was convincing people - designers and engineers - to actually use the new design system.
This experience taught me several important lessons:
6.1. Know your client (KYC)
My clients were developers with a full roadmap, tight deadlines, and limited time to learn new systems.
A design system must feel familiar, even if that means compromising on theoretical best practices.
Practicality over purity.
6.2. People follow the easiest path
If the new system is not frictionless, adoption slows down dramatically.
Ease of use wins every time - even over code perfection.
6.3. Find allies
You need people who care - even a few of them.
Looking back, a great idea would have been to assign each team 1–2 components aligned with their roadmap.
This would distribute ownership, improve knowledge sharing, and turn contributors into advocates.
6.4. Celebrate contributions
I once created a simple script to count contributions to the design system (PRs, LOC, etc.) and shared the results quarterly.
Recognising people publicly boosted engagement and encouraged others to join.
7. Conclusion
A design system is not just a UI library - it's processes, people, habits, and trust.
Technology creates the foundation, but governance and culture create the actual value.
This project wasn't an easy walk in the park - it was a real organisational and technical challenge.
But it was a successful one: we built a scalable, predictable, trustworthy system that helped us deliver features faster and with more confidence.
Feel free to connect with me on LinkedIn
🚀 More content coming soon - stay tuned!
Top comments (0)